我们可以像这样使用HTML5中的web worker:
var worker = new Worker('worker.js');
但为什么我们不能调用这样的函数?
var worker = new Worker(function(){
//do something
});
答案 0 :(得分:18)
这是网络工作者的设计方式。它们必须有自己的外部JS文件和由该文件初始化的自己的环境。出于多线程冲突的原因,他们无法与常规的全局JS空间共享环境。
不允许Web工作者直接访问全局变量的一个原因是,它需要两个环境之间的线程同步,这不是可用的东西(并且会使事情变得非常复杂)。当web worker有自己独立的全局变量时,除了通过与主JS线程正确同步的消息队列之外,他们不能搞乱主JS线程。
也许有一天,更高级的JS程序员将能够使用传统的线程同步技术来共享对公共变量的访问,但是现在两个线程之间的所有通信都必须通过消息队列,并且web worker无法访问主要的Javascript线程的环境。
答案 1 :(得分:10)
此问题已被问及before,但出于某种原因,OP决定将其删除。
我重新发布我的答案,以防需要一个方法来从函数创建Web worker。
在this post中,显示了三种从任意字符串创建Web worker的方法。在这个答案中,我使用的是第三种方法,因为它在所有环境中都受支持。
需要帮助文件:
// 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');
请注意,范围是严格分开的。变量只能使用worker.postMessage
和worker.onmessage
来回传递。所有邮件均为structured clones。
答案 2 :(得分:3)
这个答案可能有点晚了,但我写了一个库来简化网络工作者的使用,它可能适合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
}
})
答案 3 :(得分:1)
虽然它不是最优的并且在评论中已经提到过,但如果您的浏览器支持Web Worker的blobURL,则不需要外部文件。 HTML5Rocks是我代码的inspiration:
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 worker不会成功使用相对URL。 HTML5Rocks链接涵盖了这一点,但它不是原始问题的一部分。
人们报告了使用Blob URL与Web Workers的问题。我已经尝试过使用IE11(FCU附带的任何内容),MS Edge 41.16299(Fall Creator的更新),Firefox 57和Chrome 62.没有关于Safari支持的线索。我测试的那些已经有效了。
请注意,Blob构造函数调用中的“sample”和“sample_dependency”引用会隐式调用Function.prototype.toString()
作为sample.toString()
和sample_dependency.toString()
,这与调用{{1}非常不同}和toString(sample)
。
发布这个是因为它是第一个在搜索如何使用Web Workers而不请求其他文件时出现的stackoverflow。
看看Zevero的答案,他的回购中的代码看似相似。如果您更喜欢干净的包装器,那么这与他的代码大致相同。
最后 - 我在这里是一个菜鸟,所以任何/所有更正都会受到赞赏。
答案 4 :(得分:0)
通过设计Web工作者是多线程的,javascript是单线程的“ *”多个脚本不能同时运行。
答案 5 :(得分:0)
只需使用我的小插件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);
答案 6 :(得分:0)
WebWorkers在一个独立的线程中执行,因此对主线程进行无访问,在那里声明它们(反之亦然)。由此产生的范围是孤立的,并受到限制。这就是为什么,例如,您无法从工作人员中获取DOM。
因为线程之间的通信是必要的,所以有机制来实现它。标准通信机制是通过消息,使用 worker.postMessage()函数和 worker.onMessage(),事件处理程序。
有更多高级技术可用,涉及sharedArrayBuffers,但我的目标不是覆盖它们。如果您对它们感兴趣,请阅读here。
标准带给我们的是什么。 但是,ES6为我们提供了足够的工具来实现on-demmand可调用的 Threaded-Function 。
由于您可以从 Blob 构建Worker,并且您的Function可以转换为它(使用 URL.createObjectURL ),您只需要实现某种类型的两个线程中的通信层,为您处理消息,并获得自然的交互。
承诺当然是你的朋友,考虑到一切都会发生异步。
应用这一理论,您可以实现easilly,即您描述的场景。
我最近实施并发布了一个小型图书馆,它完全符合您的描述。小于2KB(缩小)。
它被称为 ParallelFunction ,它可以在github,npm和几个CDNs中使用。
如您所见,它完全符合您的要求:
// 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 ,将解决。
顺便说一句,许多其他的图书馆都存在。