可以使用 promise 来处理 JavaScript 中非常长且阻塞的循环吗?

Lui*_*ipe 4 javascript loops promise

假设我有以下for循环,这显然会阻塞事件循环一段时间:

function somethingExpensive() {
  let i = 0;
  while (true) {
    // Something expensive...
    if (++i === 1e10) return 'Some value.'
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以将该操作(for循环)包装在一个 Promise 中,这样它就不会阻塞“主线程”吗?

类似的东西:

function somethingExpensive() {
  return new Promise((resolve) => {
    let i = 0;
    while (true) {
      // Something expensive...
      if (++i === 1e10) resolve('Some value.');
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

Cer*_*nce 5

只是在有限的范围内。如果昂贵的操作发生在同一个 Javascript 环境中,那么该环境的资源将被昂贵的操作占用,无论该昂贵的操作是同步发生还是异步发生(如 a 之后Promise.resolve)。例如,当操作正在进行时,用户可能无法与页面交互。

改用 Service Worker,这样昂贵的操作就可以在完全独立的环境中进行,从而可以正常地与原始页面进行交互。例如:

const workerFn = () => {
  // something expensive
  while (true) {
  }
};
const workerFnStr = `(${workerFn})();`;
const blob = new Blob([workerFnStr], { type: 'text/javascript' });
const worker = new Worker(window.URL.createObjectURL(blob));

button.onclick = () => console.log('clicked');
Run Code Online (Sandbox Code Playgroud)
body {
  height: 1000px;
}
Run Code Online (Sandbox Code Playgroud)
<button id="button">click</button>
Run Code Online (Sandbox Code Playgroud)

那里的工作人员将消耗大量资源,但原始窗口将根据需要保持可滚动和可交互。如果没有工作人员,您将不得不忍受在昂贵的操作进行时原始窗口没有响应,或者将昂贵的操作错开到多个便宜的块中,例如,每 100 毫秒调用一次。(不过,即使使用这种方法,窗口也可能不会像人们希望的那样响应 - 使用工人更好)