Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Workers 使用 #21

Closed
Vibing opened this issue Nov 26, 2019 · 0 comments
Closed

Web Workers 使用 #21

Vibing opened this issue Nov 26, 2019 · 0 comments

Comments

@Vibing
Copy link
Owner

Vibing commented Nov 26, 2019

单线程的JavaScript

从我接触 js 的时候,经常听到一句话:js 是单线程的。
单线程意味着 js 代码在执行时,只能按编码顺序从上到下执行(暂时抛开异步方法),如果遇到计算量大、耗时长的任务,用户就能感觉到卡顿。

JavaScript 的主线程主要作用是服务与 UI 构建,如果遇到繁重任务阻塞了 UI 主线程,就会感觉到卡。

一般我们解决的方法有两个:异步、使用Web Worker

异步暂时不讨论,这里主要说 Web Worker

Web Worker

既然主线程用于构建 UI,那么为了不阻塞 UI 构建,我们将繁重任务从主线程剥离出来放到其他线程里执行,不就OK了?

使用 Web Worker 可以将 js 运行在后台线程中,由于它独立于主线程,所以不会阻塞 UI 的构建

专用线程 和 共享线程

专用线程(Dedicated Web Worker) 和共享线程(Shared Web Worker)。
专用线程只能由创建它的单个脚本使用,共享线程可以由多个脚本使用。

需要注意的点

  1. 有同源限制
  2. 无法使用 window 对象
  3. 无法访问 DOM 节点

浏览器支持情况

目前统计,目前约有 97.48% 的浏览器支持专用线程

而共享线程只有大约 36.75% 的浏览器支持

所以我们在使用它们时,不要忘记判断浏览器是否支持:

if (Worker) {
    //...
}
if (ShareWorker) {
    //...
}

使用

由于共享线程浏览器支持情况较差,本章我们只介绍专用线程。

我们创建一个文件夹,并在里面创建 index.html 和 worker.js
目录如下:

.
├── index.html
└── worker.js

index.html 代码:

<input type="text" id="ipt" value="" />
<div id="result"></div>

<script>
    const ipt = document.querySelector('#ipt');
    const worker = new Worker('worker.js');
    
    ipt.onchange = function() {
      // 通过postMessage发送消息
      worker.postMessage({ number: this.value });
    };
    
    // 通过onmessage接收消息
    worker.onmessage = function(e) {
      document.querySelector('#result').innerHTML = e.data;
    };
</script>

worker.js 代码:

// 这里的 self 类似主线程中的 window
self.onmessage = function(e) {
  self.postMessage(e.data.number * 2);
};

处理错误

在主线程中处理错误:

    // 主线程
    worker.onerror = function () {
        // ...
    }
    
    // 主线程使用专用线程
    worker.onmessageerror = function () {
        // ...
    }

在专用线程中处理错误:

    // worker 线程
    onerror = function () {
    
    }

加载外部脚本

Web Worker 提供了 importScripts() 方法,能够将外部脚本文件加载到 Wroker 中。

importScript('script1.js')
importScript('script2.js')

// 上面写法等同于
importScript('script1.js','script2.js')

子线程

Worker 可以生成子 Worker,但有两点要注意:

  • 子 Worker 必须与父网页同源
  • 子 Worker 中的 URI 相对于父 Worker 所在的位置进行解析

嵌入式 Worker

目前没有一类标签可以使 Worker 的代码像 <script> 元素一样嵌入网页中,但我们可以通过 Blob() 将页面中的 Worker 代码进行解析。

<script id="worker" type="javascript/worker">
// 这段代码不会被 JS 引擎直接解析,因为类型是 'javascript/worker'

// 在这里写 Worker 线程的逻辑
</script>
<script>
    var workerScript = document.querySelector('#worker').textContent
    var blob = new Blob(workerScript, {type: "text/javascript"})
    var worker = new Worker(window.URL.createObjectURL(blob))
</script>

相关链接

@Vibing Vibing closed this as completed Nov 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant