据我所知,web worker需要写在一个单独的JavaScript文件中,并像这样调用:

new Worker('longrunning.js')

我正在使用闭包编译器来合并和缩小我所有的JavaScript源代码,我不希望将我的worker放在单独的文件中进行分发。有什么办法可以做到吗?

new Worker(function() {
    //Long-running work here
});

既然一级函数对JavaScript如此重要,为什么标准的后台工作方式必须从web服务器加载整个其他JavaScript文件呢?


当前回答

html5rocks在HTML中嵌入web worker代码的解决方案相当糟糕。 而一团转义的JavaScript-as-a-string也不会更好,尤其是因为它使工作流程复杂化(闭包编译器不能操作字符串)。

我个人非常喜欢toString方法,但是@dan-man THAT正则表达式!

我喜欢的方法是:

// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',

function(){
    //Long-running work here
}.toString(),

')()' ], { type: 'application/javascript' } ) ),

worker = new Worker( blobURL );

// Won't be needing this anymore
URL.revokeObjectURL( blobURL );

支持是这三个表的交集:

http://caniuse.com/#feat=webworkers http://caniuse.com/#feat=blobbuilder http://caniuse.com/#feat=bloburls

然而,这对SharedWorker不起作用,因为URL必须是精确匹配的,即使可选的'name'参数匹配。对于SharedWorker,您需要一个单独的JavaScript文件。


2015年更新——ServiceWorker奇点到来

现在有一种更有效的方法来解决这个问题。 同样,将工作代码存储为函数(而不是静态字符串),并使用. tostring()进行转换,然后将代码插入CacheStorage中您选择的静态URL下。

// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
 [ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);

// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
 cache.put( '/my_workers/worker1.js',
  new Response( workerScript, { headers: {'content-type':'application/javascript'}})
 );
});

有两种可能的退路。ObjectURL和上面一样,或者更无缝地将一个真正的JavaScript文件放在/my_workers/worker1.js

这种方法的优点是:

还可以支持SharedWorkers。 选项卡可以在固定地址共享单个缓存副本。blob方法为每个选项卡增加随机objecturl。

其他回答

你可以在同一个javascript文件中使用内联的webworker。

下面的文章将帮助您轻松理解webworker及其局限性和调试webworker。

精通网络工作者

我喜欢ifbamoq给出的答案,但由于堆栈溢出的积分政策,我无法评论。因此,我将给出一个示例,展示一些正在进行的密集工作——以及它如何不锁定主线程。

如果你像我一样双击html文件,把它们当成小程序,就不会遇到空原点的CORS问题。: -)

<!DOCTYPE html> <html> <head> <title>Worker example: One-core computation</title> </head> <body> <p>The highest prime number discovered so far is: <div id="result"></div></p> </body> <script> // let worker = new Worker('WebWorker.js'); // lets skip this to avoid null origin issues let WorkerFn = (event) => { let isPrime = false; for (let n = 2; n <= 1_000_000; n++) { isPrime = true; for(let i = 2; i <= Math.sqrt(n); i++) if (n % i == 0) isPrime = false; // If you can get thru all this shit and survive, ur prime! if (isPrime) postMessage(n); } } let worker = new Worker(window.URL.createObjectURL(new Blob(["(" + WorkerFn.toString() + ")()"], {type: "text/javascript"}))); worker.onmessage = (event) => { result.innerHTML = event.data; } </script> </html>

我认为更好的方法是使用Blob对象,下面你可以看到一个简单的例子。

// create a Blob object with a worker code
var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

// create a Worker
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  console.log(e.data);
};
worker.postMessage("Send some Data"); 

另一个解决方案是将Worker包装在一个函数中,然后创建一个调用函数的blob,如下所示:

     function workerCode() {
        self.onmessage = function (e) {
          console.log("Got message from parent", e.data);
        };
        setTimeout(() => {
          self.postMessage("Message From Worker");
        }, 2000);
      }

      let blob = new Blob([
        "(" + workerCode.toString() + ")()"
      ], {type: "text/javascript"});

      // Note: window.webkitURL.createObjectURL() in Chrome 10+.
      let worker = new Worker(window.URL.createObjectURL(blob));
      worker.onmessage = function (e) {
        console.log("Received: " + e.data);
      };
      worker.postMessage("hello"); // Start the worker.

https://developer.mozilla.org/es/docs/Web/Guide/Performance/Using_web_workers

    // Syntax: asyncEval(code[, listener])

var asyncEval = (function () {

  var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");

  oParser.onmessage = function (oEvent) {
    if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
    delete aListeners[oEvent.data.id];
  };


  return function (sCode, fListener) {
    aListeners.push(fListener || null);
    oParser.postMessage({
      "id": aListeners.length - 1,
      "code": sCode
    });
  };

})();