WebWorker,这次一定会!

一些背景原因

【异步发展史,这次一定会!】中,因为js引擎是单线程的,所以我们需要异步编程,需要将耗时的操作异步处理。但是当这些执行异步任务时,它们先被放入浏览器的事件任务队列中去,等到执行栈空闲时才会按照队列先进先出的原则被一一执行,但终究还是单线程。若是复杂耗时的任务仍然会耗费较大的时间。

为了能使js引擎多线程,webworker应运而生,当然,js本身仍然是单线程,但是js运行的环境浏览器为其提供多线程。

WebWorker是什么❓

官方文档

通过使用Web Workers,Web应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。这样做的好处是可以在独立线程中执行费时的处理任务,从而允许主线程(通常是UI线程)不会因此被阻塞放慢。

好处:

  1. Worker 线程新建后,就会长时间运行

  2. 不会被主线程上的活动(比如用户点击按钮、提交表单)打断

  3. 有利于随时响应主线程的通信,并同时保证页面对用户的及时响应。

劣势:

Worker 比较耗费资源,不应该过度使用,使用完毕,请立即关闭。

一些大坑:

1. 不能跨域

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

2. DOM 限制

Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。

3.通信联系

Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。

4.脚本限制

Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。

5.文件限制

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

😈WebWorker怎么用

基本用法

1.新建一个Worker线程

//形如const myWorker = new Worker(aURL, options); aURL:js文件名 [options]一些属性
let myWorker = new Worker("worker.js");
//在chrome中不允许读取本地文件,所以最好起一个本地服务器读取或者是读取同源网络文件

2.线程通信

onmessage: 监听事件
postmessage: 传送事件

主线程文件

//当触发耗时事件时
first.onchange = function() {
  myWorker.postMessage([first.value,second.value]);
  console.log('Message posted to worker');
}

second.onchange = function() {
  myWorker.postMessage([first.value,second.value]);
  console.log('Message posted to worker');
}

worker.js

self.onmessage = function(event){
   console.log('Worker recieved message');
};

3.结束时关闭

主线程文件

myWorker.terminate();

子线程文件

self.close();

4.错误处理

主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件

//方一:
myWorker.onerror(function (event) {
});

//方二:
myWorker.addEventListener('error', function (event) {
});

5.加载其他文件

Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()

importScripts();                         /* imports nothing */
importScripts('foo.js');                 /* imports just "foo.js" */
importScripts('foo.js', 'bar.js');       /* imports two scripts */
importScripts('//example.com/hello.js'); /* You can import scripts from other origins */

6.线程间的数据通信

主线程与worker之间的通信是一种值拷贝的过程,即是传值而不是传址。实际上是先将数据JSON.stringify之后再JSON.parse。以这种拷贝的方式会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

var transfer = new ArrayBuffer(1);
worker.postMessage(transfer, [transfer]);

WebWorker的使用场合

1. 庞大复杂数学计算

2. 图像处理

通过使用从<canvas>或者<video>元素中获取的数据,可以把图像分割成几个不同的区域并且把它们推送给并行的不同Workers来做计算

3. 大量数据的请求

4. 背景数据分析

由于在使用Web Worker的时候,我们有更多潜在的CPU可用时间,我们现在可以考虑一下JavaScript中的新应用场景。例如,我们可以想像在不影响UI体验的情况下实时处理用户输入。利用这样一种可能,我们可以想像一个像Word(Office Web Apps 套装)一样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等

🌰试一试

git 地址
注意:要用http-server形式开启才能打开文件

参考

官方文档
阮一峰老师的博客
聊聊Webworker⬅️这位写的超棒 还有在线demo 建议全文细读

原文链接:juejin.im

上一篇:Flutter - Packages管理
下一篇:异步发展史,这次一定会!

相关推荐

官方社区

扫码加入 JavaScript 社区