为同源CPU密集iframe分离事件循环

时间:2014-06-23 09:38:27

标签: javascript iframe sandbox same-origin-policy

假设我有一个CPU密集型iframe 它与父页面位于同一个域中,因此交叉原点不适用,因此它共享父级的事件循环。

是否可以为iframe提供单独的JS上下文(包括单独的事件循环),以便它不会阻止父UI的使用?

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

这个问题是假设的/概念性的。我没有真正的用例。只是好奇。
我在漫游JSFiddle之类的网站如何运行用户的代码,并且显然它来自不同域的iframe(JSFiddle案例中的jshell.net)。

2 个答案:

答案 0 :(得分:2)

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

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

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

在 JSFiddle 上,一开始这有点难以看透,因为他们的 iframe 没有设置 src 属性。然而,iframe 绑定到一个表单,最终成为另一个跨域 iframe。

解决方法 - 网络工作者

正如其他人正确提到的,您可以使用 Web Worker 来生成新的 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 的优点是,它将在每次事件循环迭代后调用,而不是在 ~4ms 后调用,从而使其更快。

我们的解决方法存在的问题

我们的变通方法仅适用于我们昂贵的任务,不必经常从 DOM 中读取数据。

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

总结

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

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

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

答案 1 :(得分:1)

Javascript 是单线程的。在其他线程中执行任务的一种方式是网络工作者。但是他们无法访问 DOM。

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

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