一、概述
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 | # | 引用