4

I recently heard about the rel="noopener" attribute value that can be added to anchor tags so that the new window runs in a separate process. That got me wondering: Is it possible to create an iframe that runs in a separate process so that, for example, an infinite loop in the iframe won't cause the parent window's main thread to be blocked?

Here's some example code to observe the main-thread freeze:

<progress></progress>
<iframe srcdoc="<script>function loop() { i=0; while(i<700000000){i++}; setTimeout(loop, 2000) }; loop();</script>"></iframe>

https://jsbin.com/zabecoviwi/1/edit?html,output

Edit: Note that you can prevent the freezing by adding the sandbox attribute to the iframe, which seems to "force" the browser (Chrome, at least) to put the iframe in a separate thread, but I can't do this in my case. I am however serving the code for the iframe under a separate subdomain so I'd have thought that since it's a separate origin Chrome would put it in a separate process as it appears to do if the iframe's src is a different top-level domain.

2 Answers2

2

In some browsers, including Chrome, cross-origin iframes already run in a separate process. For example, running the following snippet in Chrome will not prevent you from scrolling in the parent Stack Overflow window:

while (true) {
}

For browsers which don't do this already, or for same origin iframes, you can make the process explicit by running the expensive tasks in a web worker in the iframe:

const workerFn = () => {
  // something expensive
  while (true) {
  }
};
const workerFnStr = `(${workerFn})();`;
const blob = new Blob([workerFnStr], { type: 'text/javascript' });
const worker = new Worker(window.URL.createObjectURL(blob));

// The worker has been created, and will continuously consume resources,
// but will not block the iframe window or the iframe's parent
body {
  height: 1000px;
}
CertainPerformance
  • 313,535
  • 40
  • 245
  • 254
  • Hmm, that's strange because the example I linked in my post freezes jsbin's main thread even though jsbin runs the javascript on a separate subdomain: `null.jsbin.com` which is thus cross-origin. Adding the `sandbox` attribute fixes is (no freezing), so maybe Chrome isn't doing the process-separation on a strictly "different-origin" basis? Maybe it's doing it by top-level domain? I'm doing a similar thing to JSbin for my site (running iframe on a subdomain) and I'm seeing the same parent-freezing behavior. –  Jun 13 '19 at 23:43
2

As of early 2021, there is now the Origin-Agent-Cluster header which allows you to request dedicated resources for an iframe. It is currently supported on Chrome (88+) with positive reception from Mozilla and Safari.

Origin-Agent-Cluster is a new HTTP response header that instructs the browser to prevent synchronous scripting access between same-site cross-origin pages. Browsers may also use Origin-Agent-Cluster as a hint that your origin should get its own, separate resources, such as a dedicated process.

[...] For example, if https://customerservicewidget.example.com expects to use lots of resources for video chat, and will be embedded on various origins throughout https://*.example.com, the team maintaining that widget could use the Origin-Agent-Cluster header to try to decrease their performance impact on embedders.

To use the Origin-Agent-Cluster header, configure your web server to send the following HTTP response header: Origin-Agent-Cluster: ?1 The value of ?1 is the structured header syntax for a boolean true value.

More details here: https://web.dev/origin-agent-cluster/

joe
  • 1,766
  • 1
  • 18
  • 27