Javascript 同一源CPU密集型iframe的单独事件循环

Javascript 同一源CPU密集型iframe的单独事件循环,javascript,iframe,sandbox,same-origin-policy,Javascript,Iframe,Sandbox,Same Origin Policy,假设我有一个CPU密集型iframe。 它与父页面位于同一域中,因此跨源不适用,因此它共享父页面的事件循环 iframe是否可以有一个单独的JS上下文(包括一个单独的事件循环),这样它就不会阻塞父级的UI 为iframe标记设置sandbox属性并不能解决这一问题,尽管iframe将被视为来自“唯一来源”的状态 这个问题是假设性的/概念性的。我没有这个真正的用例。只是好奇。 我想知道像JSFiddle这样的网站是如何运行用户代码的,很明显它是从不同域的iframe运行的(JSFiddle的例子是

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

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

iframe
标记设置
sandbox
属性并不能解决这一问题,尽管iframe将被视为来自“唯一来源”的状态

这个问题是假设性的/概念性的。我没有这个真正的用例。只是好奇。

我想知道像JSFiddle这样的网站是如何运行用户代码的,很明显它是从不同域的iframe运行的(JSFiddle的例子是jshell.net)。

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

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

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

像JSFIDLE这样的服务如何在不同的事件循环中运行用户代码? 他们没有解决实际的问题,他们只是通过使用跨原点iFrame来绕过它

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

在JSFIDLE上,这一点一开始就有点难以理解,因为它们的iframe没有
src
属性集。但是,iframe绑定到一个表单,该表单最终成为另一个跨原点iframe

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

这是可行的,因为web工作者在独立的线程()中运行

解决方法-以较小的块运行代码 正如其他人也提到的,通过在较小的块中运行代码,可以提高性能。以以下为例:

const数组=[…];//包含数百个项目的阵列
常量结果=[];
常量逐步计算=()=>{
if(array.length){
结果:push(doExpensiveCalculation(数组[0]);
数组。shift();
requestAnimationFrame(逐步计算);
}
}
逐步计算();
现在,在事件循环的每次迭代之后,一步一步地处理数组中的一项

此外,使用
requestAnimationFrame
而不是
setInterval
setTimeout
有一个优点,即它将在每次事件循环迭代后调用,而不是在~4ms后调用,使其速度更快

我们解决办法的问题 如果我们的昂贵任务不需要不断地从DOM读取数据,那么我们的变通方法只能起作用

这是一个大问题,如果我们的同一来源iframe具有昂贵的JavaScript动画,它将严重干扰,并可能导致UI滞后

总结能力 将计算转移到工作线程中,或者一步一步地进行以减少负载

但是,对于您的主要问题,我们无法为同一来源iFrame创建单独的JS上下文(目前为止)。在线JS Shell通过使用跨原点iFrame来解决这个问题


如果我们可以在合成器或光栅线程中运行JavaScript代码,这将是一件有趣的事情,因为它们应该可以访问我们的DOM,而不是web workers。

在子域中运行它?我特别要求在同一个域中运行iFrame我有一个这样的用例,我不希望嵌入的文档以任何方式阻止或减慢我的主事件循环。现有的解决方法是使用不同的子域,但我想知道是否有其他/更好的解决方案。你可以使用工作线程吗?@Keimeno工作线程可以与可以访问DOM的主进程通信。我同意你的看法,这不是建议的解决方案的答案:创建单独的js上下文。然而,这个问题表达了无响应UI的(假设)问题。这些问题可以通过我的解决方案来减少。
原始代理集群
标题上的链接答案特别有趣,似乎部分解决了这个问题和悬赏问题。问题的含义是,不同的域/源iFrame可以是在不同线程上运行的进程外iFrame,但相同的域/源iFrame通常不会这样做。使用
originagent集群
头提示相同站点的跨源帧应该在不同的线程上运行。如果iframe是完全相同的原点,它仍然不会在单独的线程上运行。