【问题标题】:Separate event-loop for same-origin CPU intensive iframe同源 CPU 密集型 iframe 的单独事件循环
【发布时间】:2014-08-13 07:18:36
【问题描述】:

假设我有一个 CPU 密集型 iframe。
它与父页面在同一个域中,因此不适用跨域,因此它共享父页面的事件循环。

是否可以为 iframe 提供一个单独的 JS 上下文(包括一个单独的事件循环),这样它就不会阻塞父级的 UI?

iframe 标签设置sandbox 属性并不能解决这个问题,尽管docs 声明iframe 将被视为来自“唯一来源”。

这个问题是假设性/概念性的。我没有一个真正的用例。只是好奇。
我在徘徊像 JSFiddle 这样的网站如何运行用户的代码,并且显然它是从来自不同域的 iframe 运行的(在 JSFiddle 的情况下是 jshell.net)。

【问题讨论】:

  • 在子域中运行它?
  • 我特意要求同一域中的 iframe
  • 我有一个用例,我不希望我的主事件循环被嵌入文档以任何方式阻塞或减慢。现有的解决方法是使用不同的子域,但我想知道是否有任何其他/更好的解决方案。
  • 可以使用工作线程吗?
  • @Keimeno,worker 可以与可以访问 DOM 的主进程通信。

标签: javascript iframe sandbox same-origin-policy


【解决方案1】:

像 JSFiddle 这样的服务如何在不同的事件循环中运行用户代码?

他们没有解决实际问题,他们只是通过使用跨域 iframe 解决问题。

例如,这在 StackBlitz 上很容易看到,它们为每个执行环境创建一个子域。

在 JSFiddle 上,起初这有点难以看穿,因为他们的 iframe 没有设置 src 属性。但是,iframe 绑定到一个表单,最终成为另一个跨域 iframe。

解决方法 - 网络工作者

正如其他人正确提到的,您可以使用网络工作者,生成新的 JS 上下文,并在那里运行一些繁重的计算。

这是可行的,因为网络工作者在隔离线程中运行 (MDN)。

解决方法 - 以较小的块运行代码

正如其他人也提到的那样,通过以较小的块运行代码可以提高性能。举个例子:

const array = [ ... ]; // array with hundreds of items
const result = [];

const stepByStepCalculation = () => {
  if (array.length) {
    result.push(doExpensiveCalculation(array[0]));
    array.shift();
    requestAnimationFrame(stepByStepCalculation);
  }
}

stepByStepCalculation();

现在,在事件循环的每次迭代之后,我们的数组中的一项正在被处理 - 一步一步。

另外,使用requestAnimationFrame 而不是setIntervalsetTimeout 的优势在于,它将在每次事件循环迭代后调用,而不是在大约 4 毫秒后调用,从而使其更快。

我们的解决方法的问题

我们的解决方法只有在我们的昂贵任务不需要不断地从 DOM 中读取时才有效。

这是个大问题,如果我们的同源 iframe 有昂贵的 JavaScript 动画,它会严重干扰并可能导致 UI 卡顿。

总结

将计算移到工作线程中,或逐步进行以减少负载。

但是,对于您的主要问题,我们无法为同源 iframe 创建单独的 JS 上下文(截至目前)。在线 JS shell 通过使用跨域 iframe 解决了这个问题。

如果我们能以某种方式在合成器或光栅线程中运行 JavaScript 代码会很有趣,因为它们应该可以访问我们的 DOM,这与 web worker 不同。

【讨论】:

    【解决方案2】:

    Javascript 是单线程的。在其他线程中执行任务的一种方法是 web-workers。但是他们无法访问 DOM。

    如果您有一个非常密集的任务会阻塞您的 UI,您可以将这些任务分成多个块,并在其间设置超时。 超时不会阻止其他代码执行。因此,如果您对此很聪明,则可以使用此技术创建时间窗口以供 UI 响应。

    This Question(和答案)处理一个非常相似的问题。

    【讨论】:

    • 我同意你的观点,这不是建议的解决方案的答案:创建一个单独的 js 上下文。然而,这个问题表达了(假设的)用户界面无响应的问题。我的解决方案可以减少这些
    • Origin-Agent-Cluster 标头上的链接答案特别有趣,似乎部分解决了问题和赏金问题。问题的含义是不同的域/源 iframe 可以是在不同线程上运行的进程外 iframe,但相同的域/源 iframe 通常不会这样做。使用Origin-Agent-Cluster 标头暗示同站点跨源帧应该在单独的线程上运行。如果 iframe 的来源完全相同,它仍然不会在单独的线程上运行。
    猜你喜欢
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多