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

new Worker('longrunning.js')

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

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

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


当前回答

我喜欢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"); 

尝试使用jThread。https://github.com/cheprasov/jThread

// You can use simple calling like this
jThread(
    function(arr){
        //... some code for Worker
        return arr;
    }
    ,function(arr){
        //... done code
    }
)( [1,2,3,4,5,6,7] ); // some params

我喜欢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>

另一个解决方案是将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.

所以我认为我们现在有了另一个很酷的选择,这要感谢ES6中的模板文字。这允许我们省去额外的worker函数(及其奇怪的作用域),只需将用于worker的代码编写为多行文本,就像我们用来存储文本的情况一样,但实际上不需要使用文档或DOM来实现。例子:

const workerScript = `
self.addEventListener('message', function(e) {
  var data = e.data;
  console.log('worker recieved: ',data);
  self.postMessage('worker added! :'+ addOne(data.value));
  self.close();//kills the worker
}, false);
`;

下面是该方法的其余要点。

请注意,我们可以将任何我们想要的额外函数依赖项拉入worker,只需将它们收集到一个数组中,并对每个函数运行. tostring,将它们简化为字符串(只要它们是函数声明就可以工作),然后将其添加到脚本字符串中。这样,我们就不必导入我们可能已经捆绑到正在编写的代码范围中的脚本。

这个特定版本唯一的缺点是lints无法检测service worker代码(因为它只是一个字符串),这对于“单独的worker函数方法”来说是一个优势。