JavaScript语言的一大特点就是单线程。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。HTML5提出 Web Worker
标准,允许JavaScript脚本创建多个线程,但是 子线程完全受主线程控制,且不得操作DOM。所以,这个新标准 并没有改变JavaScript单线程的本质
JS提供了一个 Worker
的类,当我们使用这个类的时候,它就会向 浏览器 申请一个新的线程。这个线程就用来 单独执行一个js文件。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
Web Worker 使用注意点:
同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document
、window
、parent
这些对象。但是,Worker 线程可以使用navigator
对象和location
对象。
通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过 消息 完成。
脚本限制
Worker 线程不能执行alert()
方法和confirm()
方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统 (file://)
,它所加载的脚本,必须来自网络。
var worker = new Worker("work.js");
worker.postMessage(参数); //参数就是主线程传给 Worker 的数据,可以是文本、对象等等
worker.onmessage = function (event) {
console.log(‘Received message ‘ + event.data);
}
worker.terminate();
message
事件。this.addEventListener(‘message‘, function (e) {
self.postMessage(‘You said: ‘ + e.data);
}, false)
self.postMessage(‘this is worker‘);
self.close();
// 主线程
Worker.onerror:指定 error 事件的监听函数。
//worker线程
self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
主线程给worker线程发送的数据是 文本、对象 的话是拷贝的形式发送。即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。
主线程给worker线程发送的数据是 二进制数据,但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。
原文:https://www.cnblogs.com/baboon/p/12953989.html