如何设计一个长运行javascript的函数来避免得到浏览器警告"Unresponsive Script"

How to desgin a long running javascript function to avoid getting the browser warning "Unresponsive Script"

我有一个 JavaScript 函数,可以获取几百个(!)URL。

该函数必须按顺序提取这些 URL,因此在尝试下一次提取之前必须等待一次提取。

我该如何设计或如何调用此函数,以免收到浏览器警告“Unresponsive Script”?


注意:因为带有脚本的页面被很多用户使用,所以我无法更改特定于浏览器的设置(例如dom.max_script_run_time

运行 长异步脚本会阻止页面绘制。因此,您需要将您的任务转换为“批次”,并让浏览器在每个批次 运行 之后处理其他任务。

看看这个来自 https://javascript.info/event-loop 的例子:

let i = 0;

function count() {
    // do a piece of the heavy job (*)
    do {
      i++;
      progress.innerHTML = i;
    } while (i % 1e3 != 0);

    if (i < 1e7) {
      setTimeout(count);
    }
}

count();

现在繁重的任务是分批 1000 次迭代完成,而不是一批 1e7 次迭代。

在代码中我们说:

  • 如果不是1000的倍数,则增加i。但是代码progress.innerHTML = i在循环结束前不会更新界面。
  • 一旦 i 乘以 1000,循环就会中断,另一个 batch 使用 setTimeout 被“推迟”并更新 UI。

您还可以将您的代码移动到 web worker 中,它 运行 在后台线程上运行并且不会干扰用户界面。

更新: 上面显示的 setTimeout 方法有效,但它不是一个完美的解决方案,因为:

JS 的主要脚本是 运行 在单线程上,异步操作不是 运行 在另一个线程上,它们只是被推迟到 运行 “稍后” .所以他们“总是”在 运行ning 时阻止主脚本,即使我们做了提到的 hack(当我们在做 - while 循环)。

如果我们想“真正”将繁重的任务与我们的主脚本分开,我们应该使用 Web Workers,它实际上是 运行 在另一个 OS 级别的线程上。

所以你最好的选择是使用 Web Worker 并使用 postMessage 系统传达结果。

注意:网络工作者无权访问 DOM