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

new Worker('longrunning.js')

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

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

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


当前回答

这是一个有点离题的答案,但是……您可能不需要使用网络工作者来处理浏览器上的长时间工作。

让我们假设你想要运行几次繁重的计算(就像你对数组做的那样):

const heavyFct = () => {let i = 0; while(i<1e8) {++i}}

for (let i = 0; i < 100; ++i) {
  heavyFct();
}

这将冻结您的浏览器。

为了避免这种情况,我们可以这样依赖setTimeout:

const desync = (i = 0) => {
  if (i >= 100) {return}
  heavyFct();
  setTimeout(() => desync(i + 1), 0);
}
desync();

现在,您可以在不冻结计算机的情况下运行繁重的计算

其他回答

使用我的小插件https://github.com/zevero/worker-create

var worker_url = Worker.createURL(function(e){
  self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);

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

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
    });
  };

})();

这只是上面的一个补充-我在jsFiddle中有一个很好的模板用于测试web worker。而不是Blob,它使用jsFiddles ?js api:

function workerFN() {
  self.onmessage = function(e) {
    switch(e.data.name) {
      case "" : 
      break;
      default:
        console.error("Unknown message:", e.data.name);
    }
  }
}
// This is a trick to generate real worker script that is loaded from server
var url = "/echo/js/?js="+encodeURIComponent("("+workerFN.toString()+")()");
var worker = new Worker(url);
worker.addEventListener("message", function(e) {
  switch(e.data.name) {
    case "" : 
    break;
    default:
      console.error("Unknown message:", e.data.name);
  }
})

有普通的web worker模板和共享worker模板。

我的看法是:

function BuildWorker(fn){
   var str = fn.toString().match(/^[^{]+{([\s\S]+)}\s*$/m)[1];
   return  new Worker(window.URL.createObjectURL(
                new Blob([str],{type:'text/javascript'})));
}

function createAsyncWorker(fn){
    
    // asyncworker=createAsyncWorker(function(){
    //     importScripts('my_otherscript.js');
    //     self.onmessage = function([arg1,arg2]) {
    //         self.postMessage('msg from worker');
    //     };
    // })
    // await asyncworker.postMessage('arg1','value')
    // await asyncworker.postMessage('arg1','value')
    // asyncworker.worker.terminate()
    
    var worker = BuildWorker(fn);

    function postMessage(...message){
        let external={}, promise= new Promise((resolve,reject)=>{external.resolve=resolve;external.reject=reject;})
        worker.onmessage = function(message){ external.resolve(message.data)};
        worker.postMessage(message); // Start the worker.
        return promise;
    }

    return {worker,postMessage};
}

使用的例子:

autoarima = createAsyncWorker(function(){
    importScripts("https://127.0.0.1:11000/arima.js")
    
    self.onmessage=(message)=>{
        let [action,arg1,arg2]=message.data
        if(action=='load')
        {
            ARIMAPromise.then(ARIMA1 => {
                ARIMA=ARIMA1
                autoarima = new ARIMA({ auto: true });
                //   const ts = Array(10).fill(0).map((_, i) => i + Math.random() / 5)
                //   const arima = new ARIMA({ p: 2, d: 1, q: 2, P: 0, D: 0, Q: 0, S: 0, verbose: false }).train(ts)
                //   const [pred, errors] = arima.predict(10)
                postMessage('ok')
            });
        }
        if(action=='fit')
        {
            autoarima.fit(arg1)
            postMessage('ok')
        }
        if(action=='predict')
        {
            postMessage(autoarima.predict(arg1,arg2)) 
        }
    };
})
autoarima.terminate=function(){  this.worker.terminate(); }
autoarima.load=async function(...args){return await this.postMessage('load',...args)}
autoarima.fit=async function(...args){return await this.postMessage('fit',...args)}
autoarima.predict=async function(...args){return await this.postMessage('predict',...args)}

await autoarima.load()
await autoarima.fit(b_values)
await autoarima.predict(1)