如何避免 JavaScript VM 被 CPU 绑定任务阻塞

How to avoid JavaScript VM to be blocked by CPU bound task

我在 JavaScript 中有一个 cpu 密集型任务,它在 Promise:

中执行时阻塞了虚拟机

示例如下(在浏览器中尝试):

function task() {
   return new Promise((r,s) => {
      for(var x=0; x < 1000000*1000000; x++) {
          var Y = Math.sqrt(x/2)
      }
      return r(true)
   })
}

我想避免 VM 主线程被阻塞,所以我尝试在 Promise 中使用 setTimeout 传递 resolvereject 作为上下文,如:

function task() {
   return new Promise((r,s) => {
      var self=this;
      setTimeout( function(r,s) {
        for(var x=0; x < 1000000*1000000; x++) {
           var Y = Math.sqrt( Math.sin (x/2) + Math.cos(x/2))
         }
         return r(true);
      },500,r,s);
   })
}

但没有成功。知道如何避免主线程卡住吗?

您可以使用 "Web Workers"。这样,您就可以保持符合标准。这基本上是一个后台线程(例如旧 C# 中的 BackgroundWorker)。

我不确定当前 node.js 是否支持这个,所以使用 npm web workers package

除了使用 web worker 或类似工具之外,您还可以(根据任务)将工作分解为更小的块,这些块使用 setImmediate 进行处理和安排。这个例子有点傻,但你明白了。

function brokenUpTask() {
  let x = 0;  // Keep track of progress here, not in the loop.
  const limit = 1000000;
  const chunk = 100000;
  return new Promise((resolve) => {
    function tick() {  // Work a single chunk.
      let chunkLimit = Math.min(x + chunk, limit);
      for(x = 0; x < chunkLimit; x++) {
        var Y = Math.sqrt(x/2);
      }
      if(x === limit) {  // All done?
        resolve(true);
        return;
      }
      setImmediate(tick);  // Still work to do.
    }
    tick();  // Start work.
   });
}


brokenUpTask().then(() => console.log('ok'));