为之漫笔

rel=noopener可以提升性能

为之漫笔 · 2017-05-10翻译 · 548阅读 原文链接

如果你的链接指向其他站点,那么应该使用rel="noopenter",尤其是点击后会在新标签页/窗口中打开的链接。

<a href="http://example.com" target="_blank" rel="noopener">
   Example site
</a>

如果没有这个属性,新页面就可以通过window.opener来访问你的window对象。幸好Web的源安全模型会阻止它读取你的页面,不幸的是利用某些陈旧的API可以把你的页面导航到不同的URL:window.opener.location = newURL

Web大侠Mathias Bynens曾详细写过这个问题,但我发现其实它还能提升性能。

(原文这里是一个Demo,有一个“Generate random numbers”按钮,点击可生成随机数。——译者注)

这里的随机数类似当前页面的生命体征。如果并不是每一帧都能生成随机数,说明有东西阻塞了线程。

单击下面的一个链接,打开一个需要大量JavaScript计算的页面(以下并非链接,请参见原文——译者注):

  • <a target="_blank">
  • <a target="_blank" rel="noopener">

没有rel="noopener",随机数会被新打开页面中的JavaScript阻断。不仅如此,所有主线程活动也会被阻塞,试试选择页面中的文本。但加了rel="noopener"之后,随机数生成一直保持在60fps。当然,是在Chrome或Opera中。

更新:Edge对点击任何链接都会中招儿。下面我们会详细说。

那为什么会这样?

Windows & processes

大多数浏览器都是多进程的,除了Firefox(他们正在改)。每个进程包含多个线程,包括我们常说的“主”线程。解析、样式计算、布局、绘制和非worker的JavaScript都在主线程里执行。就是说,一个域中的JavaScript与另一个标签页或窗口中的域中的JavaScript在不同的线程里。

然而,由于我们可以通过window.opener同步跨窗口地访问DOM,因此通过target="_blank"启动的窗口还在同一个进程(线程)中。通过window.open打开的iframe和窗口也一样。

rel="noopener"会阻止window.opener,因此不存在跨窗口访问。Chromium浏览器为此做过优化,会在独立的进程中打开新页面。

站点隔离

在Chrome总部,我们见证了把跨源iframe和新窗口迁移到新进程,无论是否有rel="noopener"。这意味着受限的跨窗口访问会变成异步的,这样一来的好处就是提升了安全性和性能。

与此同时,rel="noopener" 能在今天为你提供性能和安全的双重好处!

更新:Edge已经针对新窗口的情况进行了优化,iframe还没有。参见Fremy的留言。

有意思的现象:注意,我上面一直在说“域”(domain)而不是“源”(origin)。这是因为可怕的document.domain允许两个域同步地变成同一个源的部分。我去!

相关文章