一、概述
JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
Web Worker 有以下几个使用注意点。
(1)同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
(2)DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
(3)通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。
(4)脚本限制
Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。
(5)文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。
二、基本用法
2.1 主线程
主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。
var worker = new Worker('work.js');
Worker()构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。
然后,主线程调用worker.postMessage()方法,向 Worker 发消息。
worker.postMessage('Hello World'); worker.postMessage({method: 'echo', args: ['Work']});
worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。
接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。
worker.onmessage = function (event) { console.log('Received message ' + event.data); doSomething(); } function doSomething() { // 执行任务 worker.postMessage('Work done!'); }
上面代码中,事件对象的data属性可以获取 Worker 发来的数据。
Worker 完成任务以后,主线程就可以把它关掉。
worker.terminate();
2.2 Worker 线程
Worker 线程内部需要有一个监听函数,监听message事件。
self.addEventListener('message', function (e) { self.postMessage('You said: ' + e.data); }, false);
上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法。
// 写法一 this.addEventListener('message', function (e) { this.postMessage('You said: ' + e.data); }, false); // 写法二 addEventListener('message', function (e) { postMessage('You said: ' + e.data); }, false);
除了使用self.addEventListener()指定监听函数,也可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息。
根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。
self.addEventListener('message', function (e) { var data = e.data; switch (data.cmd) { case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg); self.close(); // Terminates the worker. break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false);
上面代码中,self.close()用于在 Worker 内部关闭自身。
2.3 Worker 加载脚本
Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()。
importScripts('script1.js');
该方法可以同时加载多个脚本。
importScripts('script1.js', 'script2.js');
2.4 错误处理
主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件。
worker.onerror(function (event) { console.log([ 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message ].join('')); }); // 或者 worker.addEventListener('error', function (event) { // ... });
Worker 内部也可以监听error事件。
2.5 关闭 Worker
使用完毕,为了节省系统资源,必须关闭 Worker。
// 主线程 worker.terminate(); // Worker 线程 self.close();
三、数据通信
前面说过,主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。
主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。
// 主线程 var uInt8Array = new Uint8Array(new ArrayBuffer(10)); for (var i = 0; i < uInt8Array.length; ++i) { uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...] } worker.postMessage(uInt8Array); // Worker 线程 self.onmessage = function (e) { var uInt8Array = e.data; postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString()); postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength); };
但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。
如果要直接转移数据的控制权,就要使用下面的写法。
// Transferable Objects 格式 worker.postMessage(arrayBuffer, [arrayBuffer]); // 例子 var ab = new ArrayBuffer(1); worker.postMessage(ab, [ab]);
四、同页面的 Web Worker
通常情况下,Worker 载入的是一个单独的 JavaScript 脚本文件,但是也可以载入与主线程在同一个网页的代码。
<!DOCTYPE html> <body> <script id="worker" type="app/worker"> addEventListener('message', function () { postMessage('some message'); }, false); </script> </body> </html>
上面是一段嵌入网页的脚本,注意必须指定<script>标签的type属性是一个浏览器不认识的值,上例是app/worker。
然后,读取这一段嵌入页面的脚本,用 Worker 来处理。
var blob = new Blob([document.querySelector('#worker').textContent]); var url = window.URL.createObjectURL(blob); var worker = new Worker(url); worker.onmessage = function (e) { // e.data === 'some message' };
上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。
五、实例:Worker 线程完成轮询
有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在 Worker 里面。
function createWorker(f) { var blob = new Blob(['(' + f.toString() +')()']); var url = window.URL.createObjectURL(blob); var worker = new Worker(url); return worker; } var pollingWorker = createWorker(function (e) { var cache; function compare(new, old) { ... }; setInterval(function () { fetch('/my-api-endpoint').then(function (res) { var data = res.json(); if (!compare(data, cache)) { cache = data; self.postMessage(data); } }) }, 1000) }); pollingWorker.onmessage = function () { // render data } pollingWorker.postMessage('init');
上面代码中,Worker 每秒钟轮询一次数据,然后跟缓存做比较。如果不一致,就说明服务端有了新的变化,因此就要通知主线程。
六、实例: Worker 新建 Worker
Worker 线程内部还能再新建 Worker 线程(目前只有 Firefox 浏览器支持)。下面的例子是将一个计算密集的任务,分配到10个 Worker。
主线程代码如下。
var worker = new Worker('worker.js'); worker.onmessage = function (event) { document.getElementById('result').textContent = event.data; };
Worker 线程代码如下。
// worker.js // settings var num_workers = 10; var items_per_worker = 1000000; // start the workers var result = 0; var pending_workers = num_workers; for (var i = 0; i < num_workers; i += 1) { var worker = new Worker('core.js'); worker.postMessage(i * items_per_worker); worker.postMessage((i + 1) * items_per_worker); worker.onmessage = storeResult; } // handle the results function storeResult(event) { result += event.data; pending_workers -= 1; if (pending_workers <= 0) postMessage(result); // finished! }
上面代码中,Worker 线程内部新建了10个 Worker 线程,并且依次向这10个 Worker 发送消息,告知了计算的起点和终点。计算任务脚本的代码如下。
// core.js var start; onmessage = getStart; function getStart(event) { start = event.data; onmessage = getEnd; } var end; function getEnd(event) { end = event.data; onmessage = null; work(); } function work() { var result = 0; for (var i = start; i < end; i += 1) { // perform some complex calculation here result += 1; } postMessage(result); close(); }
七、API
7.1 主线程
浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。
var myWorker = new Worker(jsUrl, options);
Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。
// 主线程 var myWorker = new Worker('worker.js', { name : 'myWorker' }); // Worker 线程 self.name // myWorker
Worker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。
- Worker.onerror:指定 error 事件的监听函数。
- Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在
Event.data属性中。- Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
- Worker.postMessage():向 Worker 线程发送消息。
- Worker.terminate():立即终止 Worker 线程。
7.2 Worker 线程
Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。
Worker 线程有一些自己的全局属性和方法。
- self.name: Worker 的名字。该属性只读,由构造函数指定。
- self.onmessage:指定
message事件的监听函数。- self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
- self.close():关闭 Worker 线程。
- self.postMessage():向产生这个 Worker 线程发送消息。
- self.importScripts():加载 JS 脚本。
(完)


森林 说:
感觉学好js,需要的知识面越来越多了,虽然看的不是很懂吧,也了解了些新东西。
2018年7月 9日 00:16 | # | 引用
无名 说:
赞,想了解下 实际项目上的使用场景!
2018年7月 9日 09:19 | # | 引用
wZi 说:
一些消耗性能的事情,例如:
上传大文件的时候,可以用这个搞.
2018年7月 9日 10:58 | # | 引用
恩赐丶解脱丿 说:
想了解实战时,可以在哪些场景中应用worker
2018年7月 9日 14:45 | # | 引用
giscafer 说:
大致就是利用线程消息来实现并行,模拟多线程。可以对比 Service Worker区别一下。
2018年7月 9日 15:41 | # | 引用
月 说:
worker.postMessage(i * items_per_worker);
worker.postMessage((i + 1) * items_per_worker);
说好的是多线程,为什么这段代码
必定是上次执行完,切换了worker中的onmessage事件,才执行下一个。
2018年7月 9日 17:25 | # | 引用
js小白 说:
javascript在奇怪的方向上越走越遠,基因決定了js最終要失敗。
2018年7月 9日 23:57 | # | 引用
lein 说:
不仅可以优化浏览器端的体验,那些使用js开发的web app也大受其益,比如Electron应用。
2018年7月10日 16:34 | # | 引用
hyrious 说:
同一个 worker 内是单线程。
2018年7月12日 08:37 | # | 引用
wwmin 说:
在 [六、实例: Worker 新建 Worker] 中的实例,三个文件都放到了一个文件夹下,worker.js 中var worker= new Worker('core.js') 为什么会报错?错误如下:Uncaught ReferenceError: Worker is not defined .难道worker中不能继续new worker ? 还是我哪里错误有误?
2018年7月12日 09:10 | # | 引用
阮一峰 说:
@wwmin:
我疏忽了,刚刚确认 Worker 新建 Worker ,目前只有 Firefox 浏览器支持。
2018年7月12日 11:28 | # | 引用
Dolov 说:
17年的时候我试着用过一次,谷歌浏览器也是可以的呀
2018年7月13日 08:57 | # | 引用
永康 说:
上传大文件如果用异步上传的话也没有性能问题吧?
2018年7月13日 17:58 | # | 引用
章鱼来 说:
阮老师,在【五、实例:Worker 线程完成轮询】代码例子里,正确的createWorker方法是:
function createWorker(f) {
var blob = new Blob(['(' + f.toString() + ')()']);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
return worker;
}
不然会报错的
2018年7月14日 11:19 | # | 引用
阮一峰 说:
@章鱼来:
谢谢指出,我改过来了。
2018年7月14日 19:06 | # | 引用
ceido 说:
2018年7月17日 09:29 | # | 引用
李帅武 说:
我觉得,wenbWorker是主动往主线程传数据,而不是主线程主动去调用它,子线程达到某个要求后才会去主动和主线程通信,这就是区别吧
2018年8月 3日 14:30 | # | 引用
superwf 说:
主进程和worker中的监听api风格不一致觉得好别扭,主进程用onmessage属性赋值,worker用addEventListener函数。这么设计有什么深意吗?统一多好啊
2018年8月14日 15:51 | # | 引用
Mickey 说:
老师你好,最近查阅了一下MDN文档,有些变化,准确的说这个名词应该是复数:web workers。具体有Worker(dedicate worker), Service Worker, Shared Worker等这些,在细节上还是有些差异的,比如GlobalScope,APIs方面。
另外,在worker线程里的navigator和location分别是WorkerNavigator和WorkerLocation的实例对象,并不完全是我们所熟悉的navigator和location。
老师若是有时间可以去重新查阅一下。
2018年8月24日 09:46 | # | 引用
哨子 说:
我觉得应该是worker线程中还是同步执行代码,当遇到postMessage()方法的时候,就应该会通知主线程。
2018年8月29日 15:31 | # | 引用
小米 说:
学到很多,补充以下。
worker对象它有以下几个全局方法:
最小化的navigator对象,包括onLine、appName、appVersion、userAgent和platform属性。
只读的location属性。
setTimeout()、setInterval()、clearTimeout()和clearTimeout()、clearInterval()方法。
XMLHttpRequest构造函数。
2018年9月 4日 00:07 | # | 引用
iggy 说:
最有意思的用法,做网页游戏,主线程渲染,worker处理数据
2018年11月23日 14:32 | # | 引用
Stay 说:
在混合app中不能使用吗?我在mui框架中使用的,但是没有效果,这是为什么呢?
2018年12月 5日 17:57 | # | 引用
123 说:
异步是利用浏览器的多线程 但是分片传输的请求创建以及回调的处理还是放在js的主线程 而利用web workers从理论上来说可以瞬间并发请求 以及回调的处理也是互不干扰 个人感觉会有一些性能上的提升 但这种提升不会特别大 个人观点 没有验证
2019年1月 7日 22:51 | # | 引用
总想造轮子 说:
写了一段计数的程序测试js的多线程,发现子线程总是要等主线程运行完之后才会运行,这是什么原因呢?
计数测试JS的多线程
var worker = new Worker("child.js");
for(let i=1;i console.log("主线程计数:" + i);
}
//child.js
for(let i=1;i console.log("子线程计数:" + i);
}
2019年1月 9日 14:09 | # | 引用
aduo 说:
因为 web worker 是相当于后台运行,只有等主线程空闲了才会执行。web worker 设计来就是要让浏览器一直运行良好,如果不让主线程先执行,你web worker 计算量大还是会卡死浏览器。那么有没有web worker 都没有什么区别了
2019年2月25日 00:27 | # | 引用
麦草CMS 说:
大而全,不如简而精。
ES3、ES5都不错。进入ES6 JavaScript的路就有点儿偏了。后面还要高一年一个版本,es2016,es2017......一个辅助性脚本语言,应该以通俗易懂、方便实用为根本。es6的很多东西些定义的都很抽象,蹩脚。就拿模块化加载来说,我只想说真蹩脚。
2019年3月14日 00:23 | # | 引用
SHR 说:
2.4 错误处理那部分,应该是
windows.onerror = function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
}
2019年3月18日 13:36 | # | 引用
jacieron 说:
目前chrome,nodejs都已支持worker,在worker创建时,第二个参数type 可以用module,这样线程中导入脚本,可以直接使用 import 或require. 线程使用中需要注意,postmessage不能高频率调用,会导致cpu和内存剧增
2019年4月23日 09:52 | # | 引用
张明一 说:
new Worker() 出来的子线程要等到主线程结束才能工作,如果主线程不结束,那子线程岂不是永远都运行不了啦
2019年5月 7日 16:15 | # | 引用
张明一 说:
“在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。” 这句话有问题,经过测试,worker 线程必须等待主线程结束才开始。
2019年5月 8日 10:03 | # | 引用
xsp 说:
worker.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
参数引用错误哟,event => e
2019年5月30日 14:24 | # | 引用
xgqfrms 说:
# another way for worker listen message
```js
// callback function
onmessage = function (e){
console.log(`\n%c 主线程 e = `, css, e);
// evt.data 接收数据
let url = e.data;
// fetch data
const datas = [];
// decodeURI()
console.log(`%c 主线程 url = `, css, `"${url}"`);
fetch(url)
.then(res => res.json())
.then(
(json) => {
// console.log(`fetched json = \n`, JSON.stringify(json, null, 4));
let userInfos = json.user;
console.log(`%c userInfos = `, css_fd, JSON.stringify(userInfos, null, 4));
datas.push(userInfos);
postMessage(userInfos);
// 发送数据
}
)
.catch(err => log(`fetch error = \n`, err));
};
```
2019年7月25日 14:10 | # | 引用
xgqfrms 说:
准备用 web workers & indexedDB 搞一个 IM APP, 不知是否适合这种场景?
2019年7月25日 18:59 | # | 引用
js小白的爸爸 说:
所以你就是个弟弟,这样的观念导致你永远是个js小白,前端菜鸟
2019年10月 5日 11:52 | # | 引用
superlu 说:
阮老师,在文章开头,关于同源限制,您是这样说的:‘分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。’。
我认为这个说法不正确,应该是:‘分配给 Worker 线程运行的脚本文件,必须与页面文档同源。’。
2019年11月16日 22:29 | # | 引用
yangsl 说:
对的,这里很容易误导
2019年11月22日 18:45 | # | 引用
shadow.li 说:
阮老师您好
想提几个问题
1. 就您了解,有哪些厂商有在使用web-worker么
2. 最近想通过创建定量(比如4个)的workers做为守护线程,将常用的算法和请求从主线程剥离,但是由于我不太会分析性能,想请问这种思路是否可行呢?
2019年12月 6日 21:10 | # | 引用
loop worker 说:
你测试过吗?
我测试过: 游戏, 我用worker循环处理数据,主线程循环渲染, 性能很好
结论:内存和cpu并不会剧增!
2019年12月 7日 15:02 | # | 引用
webwork 说:
worker 能不能和cpu核绑定?
2020年1月15日 16:18 | # | 引用
shinekidd 说:
2.4 错误处理
参数是 event ,而 console.log 里面是 e.lineno e.filename e.message
五、实例:Worker 线程完成轮询
函数 function compare(new, old) { ... } "new" 是不能当参数的
2020年3月24日 09:37 | # | 引用
一正 说:
为什么会报错?错误如下:Uncaught ReferenceError: Worker is not defined
原因:file:///D:/selftraining/html5/webworker/my_task.js像这样本地文件夹开头的访问是不行的。
要放在服务器运行才行。
解决方法:
用阮老师的代码,或者拷贝这个项目:https://github.com/mdn/simple-web-worker
用http-server开启本地服务 npm install http-server -g
然后在浏览器访问就行了。
2020年4月 7日 15:16 | # | 引用
王鑫 说:
Worker 线程完成轮询,fetch 请求跨域怎么处理,用 http-proxy,会报错 Failed to execute 'fetch' on 'WorkerGlobalScope': Failed to parse URL from,直接写全连接会报跨域问题
2020年4月27日 10:34 | # | 引用
朱捷 说:
复杂的计算,有些计算可能需要几秒钟才能算出结果的。
还有介绍轮询,轮询是一个持续消耗的过程,如果页面主线程本来就复杂,这时候就能提升体验了。
2020年5月18日 11:04 | # | 引用
oliver lou 说:
我当时看时候就觉得奇怪,为什么onerror是一个函数,今天测试,发现是阮老师写错了,onerror是用句柄的方式写的
2020年6月24日 10:20 | # | 引用
戈丶 说:
这个东西说实话,很牛逼,但是用处不是很广,而且编写麻烦,所以我已经把Worker深度封装成js的Thread的类型了,实例化Thread对象调用起来非常方便,以备不时之需!
2020年7月30日 17:09 | # | 引用
diss 说:
不然你说你是小白呢,这是早年Chromium 推的,只不过和HTML5 一起标准化了,跟JavaScript有什么关系?
2020年8月14日 09:26 | # | 引用
前端菜鸡 说:
阮老师你真的太菜了,文章不少地方都写错了
2020年10月 5日 14:29 | # | 引用
造轮子的小白 说:
一般什么业务需要用到worker分配多线程执行?既然这么做的话,和数据通信的ajax请求相同,又为什么要用worker?那和websocket又有什么区别!
2020年11月13日 16:44 | # | 引用
kai 说:
有哪位前辈能详细说说 Worker 线程轮询 吗,或者有没有什么实例。
我不太会用,使用阮老师的代码,但是出现报错,URL.createObjectURL 这里生成的临时blob://路径报错。
Uncaught (in promise) TypeError: Failed to execute 'fetch' on 'WorkerGlobalScope': Failed to parse URL from server.php
2020年12月10日 04:37 | # | 引用
DeveloperEdwinlau 说:
2021年2月20日 01:01 | # | 引用
嚯嚯嚯 说:
牛是很牛,但感觉吧这玩意还是很少用,处理异步问题还是用的async、await多些(不止我自己)
2021年4月 7日 15:48 | # | 引用
徐伟 说:
这个技术,在多个js模块进行数据交互时用起来很方便,比如在websocke通信的onmessage方法中将服务器响应的数据,回调到其它js模块,用这种手法就很爽。
2021年5月13日 21:32 | # | 引用
winda 说:
我也初次学到web worker,在web worker的特性上,我有个疑问:
就是js异步放到任务队列上的任务是不是也由浏览后台类似于web worker这样的线程去处理了???
2021年5月16日 21:46 | # | 引用
JokerSora 说:
应用场景,例如前端实现远距离分段Dijkstra算法,并行执行多段路径规划
2021年7月16日 16:12 | # | 引用
Sunny 说:
目前实际项目中使用web workers的场景有哪些?
2021年7月20日 11:07 | # | 引用
jjj 说:
菜就是菜,自己只想呆在舒适区就不要找那么多理由,社会进步首先淘汰的就是你这类人。愚昧、迂腐、无知、自以为是
2021年8月 6日 11:37 | # | 引用
刚读worker 说:
如果想加快大文件的读取与计算,可不可以创建多个worker文件加快运算速度和效率
2021年11月 2日 14:14 | # | 引用
zhangdali 说:
做了几年前端,没见有人用过worker呢
2021年11月 3日 15:43 | # | 引用
暴躁男孩 说:
函数套函数,worker里面也能创建worker,感觉JS好套娃
2021年11月 8日 09:50 | # | 引用
8mile 说:
在chrome 96.0.4664.45中,子worker使用importScripts会出现变量已经定义
例如
子worker:
let x = 1
importScripts(b.js)
// b.js
let x = 2
抛出异常 x已经被定义。我看mdn上是说 不会被覆盖,但是却抛出异常了。真奇怪
2021年12月 6日 11:18 | # | 引用
Shimon 说:
webwork中加载ffmpeg经过webassembly化的js库,并且将一些耗时操作丢到里面去操作,譬如H265软解。
2021年12月23日 16:04 | # | 引用
Torrance 说:
@8mile:
MDN 上的解释:importScripts() 方法将一个或多个脚本同步导入到工作者的作用域中。
注意这里的“作用域”,当前作用域中已经存在,再定义就会出现错误。
2022年1月13日 23:35 | # | 引用
JSRUN 说:
是个语言都支持嵌套,为什么要针对JS。
2022年2月 9日 13:17 | # | 引用
Henry 说:
最近在使用Monaco-editor的过程中了解到了 Web Worker API,搜到了阮老师这篇文章,Monaco因为语法解析需要耗费大量时间,所以用worker来新开一个线程异步处理返回结果,不影响主线程UI渲染。
楼上好多人说Web Worker 没有使用场景的时候,回过头看看自己的编辑器,是不是会有所顿悟呢。
2022年2月23日 14:49 | # | 引用
test 说:
// main
let init_wk = new Worker("./loader.wk.js")
init_wk.postMessage([1,2,3,4,5,6])
// worker
self.onmessage = message=>{
console.log(message.data,'-'+(new Date).getTime())
}
在火狐中为什么会有两条输出
2022年7月 1日 22:29 | # | 引用
橙子 说:
我项目中所经历的一个应用场景,页面保持一个ws连接,需要对推送过来的数据进行二次处理再进行分发数据到各个页面,如果放主线程中,那么页面请求数据后,每次推送过来数据都需要主线程等待数据处理完成,推送频率高后,会造成页面卡顿,无法点击的问题,后面用sharedworker,在worker里面对数据进行处理,然后再分发到主线程,处理完后,实现了多个标签页共享一个链接,然后页面也流畅了很多
2022年7月23日 16:20 | # | 引用
mamba 说:
>>2.4 错误处理 实例代码
应该是这个吧。onerror = function(e){}
onerror不是一个函数
2022年9月23日 14:54 | # | 引用
santu 说:
Worker构造函数第一个参数为网络脚本或一段js代码通过Object.createObjectURL生成的url,不得为本地脚本。那么这个js远程文件或这段js脚本是用来做耗时操作的吧?比如文章中举出的轮询查状态.
2023年7月26日 14:38 | # | 引用
chd 说:
实际上不太一样,可以参考mdn里的worker简介,因为js是单线程,所以在执行一个大型计算的时候,cpu被一个任务完全占用,页面会失去响应。
promise,ajax虽然是异步,但还是单线程,按我的理解,就是cpu在多个任务之间不断地切换。worker是真正的多线程,区别就是如果cpu没有余力了就用worker,cpu有余力的情况下async,await就够用了。
2023年7月29日 15:45 | # | 引用
matt 说:
在进行大批量数据计算的时候可以采用worker的形式,将计算量放到后台worker当中计算之后返回到主线程,让主线程只负责读,子线程负责写,这样大大优化了性能开销
2023年10月13日 15:06 | # | 引用
小林 说:
开发中终于找到了一个业务场景可以用下worker,但却发现一个可以说绕不过去的问题,就是这段【Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。】,无法使用本地脚本如何配合自身的业务呢,是我对这个“本地文件”的理解有误吗?(我的设想:写一个分片上传js,再使用worker执行它),但在 new Worker(src/script/upload.js) 就出错了,是我误解了 worker 的使用吗,有没有大佬指点一下(抱拳
2023年10月19日 17:35 | # | 引用
wit 说:
之前项目运用过几次,且效果非常好,有一个场景: 需要使用FileReader同时读取大量的文件,然后发送给服务端。
还有一个最简单的测试场景,当用户拖入txt文本,并解析txt文本的内容,如果用户有上百万的数据,使用该方案,会有意想不到的效果。
2024年10月21日 16:23 | # | 引用
在下毛毛雨 说:
Worker 线程中虽然可以使用 XMLHttpRequest 发出 AJAX 请求,但只能进行异步请求,同步请求是不被支持的。
2024年11月 6日 19:23 | # | 引用
不愿意透露真实姓名的杨彬 说:
@chd:
感谢你的评论分享,使我真正理解web worker又更进了一步
2024年12月12日 15:41 | # | 引用
噗噗西 说:
写得真好,看完后感觉自己又行了。
2025年1月22日 10:51 | # | 引用
Lyeebn 说:
另,Worker(url,option)
option 对象的键只支持 name、credentials、type,其它键传了也没用,
postMessage() 不能处理 function / error 对象,
除了 blob url 外,也可以把 code 通过 urldata(data:script/javascript; code)方法硬编进去
2025年4月17日 16:39 | # | 引用