WebWorkers 上手

參考 https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers
與 node 的結(jié)合使用在 下一篇

相當(dāng)于瀏覽器可以執(zhí)行多線程代碼,且不阻塞頁(yè)面。流程大致:

  • 主線程創(chuàng)建 Worker,監(jiān)聽(tīng)子線程的消息
  • 子線程計(jì)算完成給主線程發(fā)消息
  • 結(jié)束子進(jìn)程
    但是,
  • 不可操作 dom
  • 不可操作本地文件
  • 線程間消息的傳遞,是以值復(fù)制的方式

demo_workers.js

let i = 0;

setInterval(() => {
    i++;
    // 向?yàn)g覽器主線程發(fā)消息
    postMessage({count: i});
}, 1000);

// 接受主線程的消息
onmessage = (e) => {
    i = e.data;
}

index.html

<html>
  <head>
    <title>Web Workers Demo</title>
  </head>

  <body>
    <div id="count"></div>
    <script type="text/javascript">
      if (typeof Worker !== "undefined") {
        // 創(chuàng)建一個(gè)新的 web worker 對(duì)象,然后運(yùn)行 "demo_workers.js" 中的代碼
        let w = new Worker("http://localhost:8080/static/demo_worker.js");
        // 監(jiān)聽(tīng) web worker 發(fā)回的消息
        w.onmessage = (event) => {
          // 發(fā)回的消息 event 可以是一個(gè)對(duì)象
          document.getElementById("count").innerHTML = event.data.count;
          if (event.data.count == 10) {
            // 向 web worker 發(fā)消息
            w.postMessage(90);
          }
          if (event.data.count == 100) {
            // 終止 Web Worker(不終止不知道會(huì)不會(huì)內(nèi)存泄露,或一直監(jiān)聽(tīng)浪費(fèi)資源)
            w.terminate();
            document.getElementById("count").innerHTML +=
              "WebWorkers運(yùn)行已終止";
          }
        };
        // 錯(cuò)誤監(jiān)聽(tīng)
        w.onerror = function (error) {
          console.error(
            "Worker error: " +
              error.message +
              ",file: " +
              error.filename +
              ", line: " +
              error.lineno +
              "\n"
          );
          throw error;
        };
      } else {
        document.getElementById("count").innerHTML =
          "你的瀏覽器不支付WebWorkers";
      }
    </script>
  </body>
</html>

語(yǔ)法

主進(jìn)程:

// 創(chuàng)建對(duì)象
var worker = new Worker("/static/download.js");
// 發(fā)送消息(給worker)
worker.postMessage({ cmd: "download", params: { qingguo_bookid: "" } });
// 監(jiān)聽(tīng)(worker的)消息
worker.onmessage = function (event) {
  console.log("Received message " + event.data);
  // 主進(jìn)程關(guān)閉worker
  // worker.terminate();
};
// 監(jiān)聽(tīng)(worker的)錯(cuò)誤
worker.onerror = function (event) {
  console.log(
    ["ERROR: Line ", e.lineno, " in ", e.filename, ": ", e.message].join("")
  );
};

worker:

// 監(jiān)聽(tīng)主進(jìn)程消息
// self => worker的this對(duì)象
self.addEventListener(
  "message",
  function (e) {
    // 發(fā)送消息(給主進(jìn)程)
    self.postMessage("You said: " + e);
    // worker關(guān)閉自己
    self.close();
  },
  false
);

生成 subworker

如果需要的話 worker 能夠生成更多的 worker。這就是所謂的 subworker,它們必須托管在同源的父頁(yè)面內(nèi)。而且,subworker 解析 URI 時(shí)會(huì)相對(duì)于父 worker 的地址而不是自身頁(yè)面的地址。這使得 worker 更容易記錄它們之間的依賴關(guān)系。

共享 worker

一個(gè)共享 worker 可以被多個(gè)腳本使用——即使這些腳本正在被不同的 window、iframe 或者 worker 訪問(wèn)

vue 中使用 webworker,基于 worker-loader

中文 API: https://doc.codingdict.com/webpack-cn-doc/loaders/worker-loader/

cnpm i -D worker-loader
    chainWebpack: config => {
        config.module
            .rule('worker-loader')
            .test(/\.worker\.js$/)
            .use('worker-loader')
            .loader('worker-loader')
            .end()
    }
import WebWorker from './my.worker.js';

if (Worker) {
const worker = new ReqWebWorker();
worker.onerror = ...
worker.onmessage = ...
worker.postMessage(...);

注意:

  • WebWorker 腳本文件必須與父頁(yè)面相源;
  • WebWorker 加載耗資源、耗時(shí)(初始化線程、事件隊(duì)列等),具有不可忽略的啟動(dòng)延遲,日志打印常在主線程之后,在通過(guò)日志確定操作順序時(shí)須當(dāng)心;
  • self.close()不是同步的;
  • worker.terminate()是同步的;
  • self.importScripts()沒(méi)有 CORS 限制,類似于<script>引入
  • postMessage傳遞的數(shù)據(jù):結(jié)構(gòu)化克隆算法(structured clone algorithm)、可轉(zhuǎn)移對(duì)象(transferable objects)和共享數(shù)組緩沖區(qū)(shared array buffers)。
    • 克隆 Error 對(duì)象、Function 對(duì)象或 DOM 節(jié)點(diǎn)會(huì)拋出錯(cuò)誤。
    • 可轉(zhuǎn)移對(duì)象有:ArrayBuffer\MessagePort\ImageBitmap\OffscreenCanvas,ArrayBuffer 的內(nèi)存從父上下文轉(zhuǎn)移到了工作者線程
    • SharedArrayBuffer 兼容性有問(wèn)題
  • navigator.hardwareConcurrency屬性返回的系統(tǒng)可用的核心數(shù)量,可做為線程池大小的依據(jù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??隨著 HTML5 的出現(xiàn),面向未來(lái) Web 應(yīng)用的 JavaScript API 也得到了極大的發(fā)展。這些 A...
    霜天曉閱讀 1,172評(píng)論 0 0
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,394評(píng)論 1 21
  • 島上教堂 島上餐館不多,絕大多數(shù)游客習(xí)慣于在島上自己采購(gòu)食材,然后自己在客棧做,更多是請(qǐng)客棧老板加工,收加工...
    佳佳的寶瓶子閱讀 425評(píng)論 0 0
  • 8月6日 周五 青島 陰 有些事情應(yīng)該歸結(jié)于昨天,今天來(lái)述說(shuō)時(shí)已經(jīng)有了那么一些模糊的印記。時(shí)間確實(shí)是一...
    小海涵秋閱讀 555評(píng)論 3 8

友情鏈接更多精彩內(nèi)容