上面代码中,主线程新建了一个 Worker 线程。该线程与主线程之间会有一个通信渠道,主线程通过w.postMessage向 Worker 线程发消息,同时通过message事件监听 Worker 线程的回应。

    1. // 主线程
    2. w.postMessage('hi');
    3. w.onmessage = function (ev) {
    4. console.log(ev.data);
    5. }

    上面代码中,主线程先发一个消息hi,然后在监听到 Worker 线程的回应后,就将其打印出来。

    线程之间的数据交换可以是各种格式,不仅仅是字符串,也可以是二进制数据。这种交换采用的是复制机制,即一个进程将需要分享的数据复制一份,通过postMessage方法交给另一个进程。如果数据量比较大,这种通信的效率显然比较低。很容易想到,这时可以留出一块内存区域,由主线程与 Worker 线程共享,两方都可以读写,那么就会大大提高效率,协作起来也会比较简单(不像postMessage那么麻烦)。

    ES2017 引入,允许 Worker 线程与主线程共享同一块内存。SharedArrayBuffer的 API 与ArrayBuffer一模一样,唯一的区别是后者无法共享数据。

    1. // 新建 1KB 共享内存
    2. const sharedBuffer = new SharedArrayBuffer(1024);
    3. // 主线程将共享内存的地址发送出去
    4. w.postMessage(sharedBuffer);
    5. // 在共享内存上建立视图,供写入数据
    6. const sharedArray = new Int32Array(sharedBuffer);

    Worker 线程从事件的data属性上面取到数据。

    共享内存也可以在 Worker 线程创建,发给主线程。

    1. const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 100000);
    2. // 建立 32 位整数视图
    3. // 新建一个质数生成器
    4. const primes = new PrimeGenerator();
    5. // 将 10 万个质数,写入这段内存空间
    6. for ( let i=0 ; i < ia.length ; i++ )
    7. ia[i] = primes.next();
    8. // 向 Worker 线程发送这段共享内存

    Worker 线程收到数据后的处理如下。