我们可以像这样在 HTML5 中使用 web worker:
var worker = new Worker('worker.js');
但是为什么我们不能调用这样的函数呢?
var worker = new Worker(function(){
//do something
});
我们可以像这样在 HTML5 中使用 web worker:
var worker = new Worker('worker.js');
但是为什么我们不能调用这样的函数呢?
var worker = new Worker(function(){
//do something
});
这就是网络工作者的设计方式。他们必须有自己的外部 JS 文件和由该文件初始化的自己的环境。由于多线程冲突的原因,它们无法与您的常规全局 JS 空间共享环境。
不允许网络工作者直接访问您的全局变量的一个原因是,它需要两个环境之间的线程同步,这是不可用的(这会使事情变得非常复杂)。当 web worker 有自己独立的全局变量时,它们不能与主 JS 线程混淆,除非通过与主 JS 线程正确同步的消息队列。
也许有一天,更高级的 JS 程序员将能够使用传统的线程同步技术来共享对公共变量的访问,但目前两个线程之间的所有通信都必须通过消息队列,并且 web worker 无法访问主 Javascript 线程的环境。
之前有人问过这个问题,但由于某种原因,OP决定删除它。
我重新发布我的答案,以防有人需要一种从函数创建 Web 工作者的方法。
在这篇文章中,展示了三种从任意字符串创建 Web 工作者的方法。在这个答案中,我使用的是第三种方法,因为它在所有环境中都受支持。
需要一个帮助文件:
// Worker-helper.js
self.onmessage = function(e) {
self.onmessage = null; // Clean-up
eval(e.data);
};
在您的实际 Worker 中,此帮助文件的使用如下:
// Create a Web Worker from a function, which fully runs in the scope of a new
// Worker
function spawnWorker(func) {
// Stringify the code. Example: (function(){/*logic*/}).call(self);
var code = '(' + func + ').call(self);';
var worker = new Worker('Worker-helper.js');
// Initialise worker
worker.postMessage(code);
return worker;
}
var worker = spawnWorker(function() {
// This function runs in the context of a separate Worker
self.onmessage = function(e) {
// Example: Throw any messages back
self.postMessage(e.data);
};
// etc..
});
worker.onmessage = function() {
// logic ...
};
worker.postMessage('Example');
请注意,范围是严格分开的。变量只能使用 and 来回worker.postMessage
传递worker.onmessage
。所有消息都是结构化的克隆。
这个答案可能有点晚了,但我写了一个库来简化网络工作者的使用,它可能适合 OP 的需要。看看:https ://github.com/derekchiang/simple-worker
它允许您执行以下操作:
SimpleWorker.run({
func: intensiveFunction,
args: [123456],
success: function(res) {
// do whatever you want
},
error: function(err) {
// do whatever you want
}
})
WebWorkers 在独立线程中执行,因此无法访问您声明它们的主线程(反之亦然)。生成的范围是孤立的和受限的。这就是为什么,例如,您不能从工作人员内部访问 DOM。
因为线程之间的通信是必要的,所以有一些机制可以完成它。标准的通信机制是通过消息,使用worker.postMessage()函数和 worker.onMessage()事件处理程序。
可以使用更高级的技术,包括 sharedArrayBuffers,但我的目标不是介绍它们。如果您对它们感兴趣,请阅读此处。
这就是标准带给我们的。然而,ES6 为我们提供了足够的工具来实现按需调用的 Threaded-Function。
由于您可以从Blob构建一个 Worker ,并且您的 Function 可以转换为它(使用URL.createObjectURL),您只需要在两个线程中实现某种通信层,为您处理消息,并获得一个自然的相互作用。
考虑到一切都会异步发生, Promises当然是你的朋友。
应用这个理论,您可以轻松实现您描述的场景。
我最近实现并发布了一个小型库,它完全符合您的描述。小于 2KB(缩小)。
它称为ParallelFunction,可在github、npm和几个CDN中使用。
如您所见,它完全符合您的要求:
// Your function...
let calculatePi = new ParallelFunction( function(n){
// n determines the precision , and in consequence
// the computing time to complete
var v = 0;
for(let i=1; i<=n; i+=4) v += ( 1/i ) - ( 1/(i+2) );
return 4*v;
});
// Your async call...
calculatePi(1000000).then( r=> console.log(r) );
// if you are inside an async function you can use await...
( async function(){
let result = await calculatePi(1000000);
console.log( result );
})()
// once you are done with it...
calculatePi.destroy();
初始化后,您可以根据需要多次调用您的函数。当您的函数完成执行时,将返回一个Promise并解决。
顺便说一句,存在许多其他库。
只需使用我的小插件https://github.com/zevero/worker-create
做
var worker_url = Worker.create(function(e){
self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);
虽然它不是最佳的并且在评论中提到过,但如果您的浏览器支持 Web Workers 的 blobURL,则不需要外部文件。HTML5Rocks 是我代码的灵感来源:
function sample(e)
{
postMessage(sample_dependency());
}
function sample_dependency()
{
return "BlobURLs rock!";
}
var blob = new Blob(["onmessage = " + sample + "\n" + sample_dependency]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(e)
{
console.log(e.data);
};
worker.postMessage("");
注意事项:
Blob 工作人员将无法成功使用相对 URL。HTML5Rocks 链接涵盖了这一点,但它不是原始问题的一部分。
人们报告了将 Blob URL 与 Web Worker 一起使用的问题。我已经在 IE11(FCU 附带的任何版本)、MS Edge 41.16299(Fall Creator's Update)、Firefox 57 和 Chrome 62 上进行了尝试。不知道是否支持 Safari。我测试过的那些已经奏效了。
请注意,Blob 构造函数调用中的“sample”和“sample_dependency”引用隐式调用Function.prototype.toString()
as sample.toString()
and ,这与调用andsample_dependency.toString()
非常不同。toString(sample)
toString(sample_dependency)
发布此内容是因为它是在搜索如何使用 Web Worker 而无需请求其他文件时出现的第一个 stackoverflow。
看看 Zevero 的答案,他的 repo 中的代码看起来很相似。如果您更喜欢干净的包装器,这大概就是他的代码所做的。
最后——我是这里的菜鸟,所以任何/所有的更正都值得赞赏。
按照设计,web worker 是多线程的,javascript 是单线程的“ *”多个脚本不能同时运行。