rel=noopener可以提升性能
原文链接: jakearchibald.com
如果你的链接指向其他站点,那么应该使用rel="noopener"
,尤其是点击后会在新标签页/窗口中打开的链接。
<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
允许两个域同步地变成同一个源的部分。我去!