web worker小记

135 阅读3分钟

web worker小记

前瞻

JS是单线程的,这就意味着我们在一个标签上就浪费了多核能力。 JS与UI共用同一个线程,我们在使用JS来运行CPU密集型任务 或者是 阻塞JS时,UI线程也会阻塞。这是我们不想看到的。

web worker的作用就是弥补这个缺陷而产生的,为JS提供了多线程能力。

他可以让主线程去创建worker线程,然后分配一些任务给它运行。

主线程在运行的时候,worker线程也在后台运行,两者是互不干扰的。但是worker线程一旦创建,就会一直运行,随时等待主线程传输信息,这也就意味着它是比较消耗资源的(以内一直运行),所以不应该过度使用,使用完毕后应当及时关闭。

简单使用

  1. worker的脚本文件必须与主JS脚本文件同源。
  2. 无法读取Dom,Bom可以。
  3. 不在同一个上下文环境,需要通过消息API传输信息。
  4. alert,confirm不被允许,但可以使用ajax。
  5. 无法读取本地文件,即不能打开本机的文件系统(file://)
// 使用Worker构造函数构造worker实例
// 参数为脚本文件(必须按照同源政策请求网络的Js文件)
const worker = new Worker('work.js')
// 主线程 传输信息/监听信息(可以使任何类型的数据)
worker.postMessage('hello, bbd');
worker.onmessage = (e) => {
	console.log(e.data)
}

// worker子线程只需要使用Dom3监听相应事件

// 以下使用this,但使用self可能更加直观且不易出错。
this.addEventListener('messafe', (e) => {
	this.postMessage('sss')
})

也可以直接 this.onmessage

wroker内如何加载脚本

// 可以加载多个脚本
importScripts('script1.js');

错误处理

// 如果worker发生错误就会触发
worker.onerror(function (event) {
  console.log(event)
});

// 或者
worker.addEventListener('error', function (event) {
  // ...
});

关闭worker

// 主线程
worker.terminate()
// worker自身
self.close()

数据通信

前面提到,信息传输可以是任何数据。需要注意的是这种传输的关系是拷贝。是传值非传址。

我们也可以传输文件给worker线程,但是我们提到,这种传值是通过拷贝关系的,不可能我们在前端计算10G大小的文件的时候,把10G都拷贝到worker上去。我们可以吧数据直接转给worker线程,主线程不在享有文件数据。也防止了多个线程同时修改数据的麻烦。

// Transferable Objects 格式
worker.postMessage(arrayBuffer, [arrayBuffer]);

// 例子
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);

同页面使用(一般不使用)

一般来说worker都会单独载入一个JS文件,但是也可以载入与主线程在同一个html页面的代码

// 这里需要注意,必须指定一个html无法识别的type
<!DOCTYPE html>
  <body>
    <script id="worker" type="app/worker">
      addEventListener('message', function () {
        postMessage('some message');
      }, false);
    </script>
  </body>
</html>
// 获取上面所写的js内容,转变为文本数据
var blob = new Blob([document.querySelector('#worker').textContent]);
// 然后使用它创建一个生产url
// worker再加载url完成创建
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);

worker.onmessage = function (e) {
  // e.data === 'some message'
};

实战中可以使用到,例如轮询问,计算hash值等等。