与setTimeout(0)相比,有更快的方法来产生Javascript事件循环吗?

问题描述 投票:1回答:1

我正在尝试编写一个执行可中断计算的网络工作者。我知道的唯一方法(Worker.terminate()除外)是定期屈服于消息循环,以便它可以检查是否有任何新消息。例如,该网络工作者计算从0到data的整数之和,但是如果在计算过程中向其发送新消息,它将取消计算并开始新的计算。

let currentTask = {
  cancelled: false,
}

onmessage = event => {
  // Cancel the current task if there is one.
  currentTask.cancelled = true;

  // Make a new task (this takes advantage of objects being references in Javascript).
  currentTask = {
    cancelled: false,
  };
  performComputation(currentTask, event.data);
}

// Wait for setTimeout(0) to complete, so that the event loop can receive any pending messages.
function yieldToMacrotasks() {
  return new Promise((resolve) => setTimeout(resolve));
}

async function performComputation(task, data) {
  let total = 0;

  while (data !== 0) {
    // Do a little bit of computation.
    total += data;
    --data;

    // Yield to the event loop.
    await yieldToMacrotasks();

    // Check if this task has been superceded by another one.
    if (task.cancelled) {
      return;
    }
  }

  // Return the result.
  postMessage(total);
}

这有效,但速度慢得惊人。平均而言,while循环的每次迭代在我的计算机上花费4毫秒!如果您希望取消很快发生,那将是一笔巨大的开销。

为什么这么慢?有没有更快的方法呢?

javascript settimeout web-worker event-loop
1个回答
0
投票

是,消息队列比超时队列具有更高的重要性,因此将以更高的频率触发。

您可以使用MessageChannel API轻松绑定到该队列:

let i = 0;
const channel = new MessageChannel();
channel.port1.onmessage = doSomething;

function doSomething() {
  i++;
  // loop
  channel.port2.postMessage("");
}
doSomething();

// just to log
requestAnimationFrame( display );
function display() {
  log.textContent = i;
  requestAnimationFrame( display );
}
<pre id="log"></pre>

现在,您可能还希望每个事件循环批处理同一轮操作的几轮。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.