36

我们可以像这样在 HTML5 中使用 web worker:

var worker = new Worker('worker.js');

但是为什么我们不能调用这样的函数呢?

var worker = new Worker(function(){
    //do something
});
4

7 回答 7

28

这就是网络工作者的设计方式。他们必须有自己的外部 JS 文件和由该文件初始化的自己的环境。由于多线程冲突的原因,它们无法与您的常规全局 JS 空间共享环境。

不允许网络工作者直接访问您的全局变量的一个原因是,它需要两个环境之间的线程同步,这是不可用的(这会使事情变得非常复杂)。当 web worker 有自己独立的全局变量时,它们不能与主 JS 线程混淆,除非通过与主 JS 线程正确同步的消息队列。

也许有一天,更高级的 JS 程序员将能够使用传统的线程同步技术来共享对公共变量的访问,但目前两个线程之间的所有通信都必须通过消息队列,并且 web worker 无法访问主 Javascript 线程的环境。

于 2012-07-06T02:19:20.153 回答
10

之前有人问这个问题,但由于某种原因,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。所有消息都是结构化的克隆

于 2012-07-08T09:05:22.067 回答
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
  }
})
于 2013-07-14T03:13:56.150 回答
2

WebWorkers 要点

WebWorkers 在独立线程中执行,因此无法访问您声明它们的主线程(反之亦然)。生成的范围是孤立的和受限的。这就是为什么,例如,您不能从工作人员内部访问 DOM。


与 WebWorkers 的通信

因为线程之间的通信是必要的,所以有一些机制可以完成它。标准的通信机制是通过消息,使用worker.postMessage()函数和 worker.onMessage()事件处理程序。

可以使用更高级的技术,包括 sharedArrayBuffers,但我的目标不是介绍它们。如果您对它们感兴趣,请阅读此处


线程函数

这就是标准带给我们的。然而,ES6 为我们提供了足够的工具来实现按需调用的 Threaded-Function

由于您可以从Blob构建一个 Worker ,并且您的 Function 可以转换为它(使用URL.createObjectURL),您只需要在两个线程中实现某种通信层,为您处理消息,并获得一个自然的相互作用。

考虑到一切都会异步发生, Promises当然是你的朋友。

应用这个理论,您可以轻松实现您描述的场景。


我个人的做法:ParallelFunction

我最近实现并发布了一个小型库,它完全符合您的描述。小于 2KB(缩小)。

它称为ParallelFunction,可在githubnpm和几个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并解决。

顺便说一句,存在许多其他库。

于 2018-04-24T02:45:49.547 回答
1

只需使用我的小插件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);
于 2015-10-18T12:51:53.450 回答
1

虽然它不是最佳的并且在评论中提到过,但如果您的浏览器支持 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 中的代码看起来很相似。如果您更喜欢干净的包装器,这大概就是他的代码所做的。

最后——我是这里的菜鸟,所以任何/所有的更正都值得赞赏。

于 2017-11-30T20:46:55.433 回答
0

按照设计,web worker 是多线程的,javascript 是单线程的“ *”多个脚本不能同时运行。

参考:http ://www.html5rocks.com/en/tutorials/workers/basics/

于 2012-07-06T02:20:21.013 回答