在【异步发展史,此次必定会!】中,由于js引擎是单线程的,因此咱们须要异步编程,须要将耗时的操做异步处理。可是当这些执行异步任务时,它们先被放入浏览器的事件任务队列中去,等到执行栈空闲时才会按照队列先进先出的原则被一一执行,但终究仍是单线程。如果复杂耗时的任务仍然会耗费较大的时间。html
为了能使js引擎多线程,webworker应运而生,固然,js自己仍然是单线程,可是js运行的环境浏览器为其提供多线程。git
官方文档github
经过使用Web Workers,Web应用程序能够在独立于主线程的后台线程中,运行一个脚本操做。这样作的好处是能够在独立线程中执行费时的处理任务,从而容许主线程(一般是UI线程)不会所以被阻塞放慢。web
Worker 线程新建后,就会长时间运行chrome
不会被主线程上的活动(好比用户点击按钮、提交表单)打断编程
有利于随时响应主线程的通讯,并同时保证页面对用户的及时响应。canvas
Worker 比较耗费资源,不该该过分使用,使用完毕,请当即关闭。segmentfault
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。跨域
Worker 线程所在的全局对象,与主线程不同,没法读取主线程所在网页的 DOM 对象,也没法使用document、window、parent这些对象。可是,Worker 线程能够navigator对象和location对象。浏览器
Worker 线程和主线程不在同一个上下文环境,它们不能直接通讯,必须经过消息完成。
Worker 线程不能执行alert()方法和confirm()方法,但可使用 XMLHttpRequest 对象发出 AJAX 请求。
Worker 线程没法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
//形如const myWorker = new Worker(aURL, options); aURL:js文件名 [options]一些属性
let myWorker = new Worker("worker.js");
//在chrome中不容许读取本地文件,因此最好起一个本地服务器读取或者是读取同源网络文件
复制代码
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');
};
复制代码
主线程文件
myWorker.terminate();
复制代码
子线程文件
self.close();
复制代码
主线程能够监听 Worker 是否发生错误。若是发生错误,Worker 会触发主线程的error事件
//方一:
myWorker.onerror(function (event) {
});
//方二:
myWorker.addEventListener('error', function (event) {
});
复制代码
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 */
复制代码
主线程与worker之间的通讯是一种值拷贝的过程,便是传值而不是传址。其实是先将数据JSON.stringify以后再JSON.parse。以这种拷贝的方式会形成性能问题。好比,主线程向 Worker 发送一个 500MB 文件,默认状况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 容许主线程把二进制数据直接转移给子线程,可是一旦转移,主线程就没法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫作Transferable Objects。这使得主线程能够快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就很是方便了,不会产生性能负担。
var transfer = new ArrayBuffer(1);
worker.postMessage(transfer, [transfer]);
复制代码
经过使用从<canvas>
或者<video>
元素中获取的数据,能够把图像分割成几个不一样的区域而且把它们推送给并行的不一样Workers来作计算
因为在使用Web Worker的时候,咱们有更多潜在的CPU可用时间,咱们如今能够考虑一下JavaScript中的新应用场景。例如,咱们能够想像在不影响UI体验的状况下实时处理用户输入。利用这样一种可能,咱们能够想像一个像Word(Office Web Apps 套装)同样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等
git 地址
注意:要用http-server形式开启才能打开文件
官方文档
阮一峰老师的博客
聊聊Webworker ⬅️这位写的超棒 还有在线demo 建议全文细读