产品需求来啦:点击页面上某个东西,要在新窗口中打开一个页面,注意!要在新窗口中打开。你呵呵一笑,太简单了:
target="_blank"
属性搞定。window.open(url)
搞定。如果你人品比较好,你的页面可以顺利地运行到下线为止。但如果你脸比较黑,可能会遇到以下问题:
WTF?
步骤:
步骤:
用简单地方式(背景中提到的)在新窗口中打开新页面会有一些问题。问题分为安全和性能两方面。机智的读者会发现上面的两个例子中分别复现了安全和性能问题(讲道理,第2个例子同时展现了安全和性能问题)
使用a标签的target="_blank"
属性,或者window.open(url)
在新窗口中打开页面时,会存在潜在的安全问题。为什么呢?这个锅是一个叫opener
的全局对象的锅。
回到例子1,可以自己动手尝试,在新打开的那个页面中,打开console, 输入opener
,可以看到这个对象,正是打开本页面的父页面的窗口对象。如果父页面和新开窗口中的页面是不同域名的,浏览器会禁止新窗口访问opener中的内容。但是有一个操作除外:可以通过window.opener.location = newURL
来重写父页面的url,即使与父窗口的页面不同域。
例子1就是利用这个方式,将父窗口的链接悄悄地替换成了钓鱼页面的地址。刚好父窗口的原始页面没有做防止被iframe嵌入,可以简单地通过iframe做一个极真实的钓鱼页面。如果不看url根本区分不出来是钓鱼页面(父窗口刚打开的时候好好的,谁会关注到这个url居然悄悄地变了呢?)
除了安全问题,例子2中还展示了简单地在新窗口中打开页面的性能问题。源页面中鬼畜的随机数之所以会卡顿,也是受新打开的窗口中的页面影响。在例子2中,新页面中有一个定时器,每隔一段时间就有一个持续的循环,这个循环在阻塞新页面本身的js线程的同时,也阻塞了opener(也就是打开新页面的父窗口)里的js线程。如果再搞得狠一些,父窗口中的页面交互可以寸步难行。
为什么新窗口中的页面会影响父页面的线程呢?chrome不是每个标签页一个单独的进程?然后进程内包含若干线程吗?
确实,chrome有不同的标签页面使用不同进程和线程,但是有个例外,通过a标签的target="_blank"
属性,或者window.open(url)
在新窗口中打开页面, 会与父窗口共用进程和线程。为什么呢?还是因为opener。。。。因为opener里有DOM信息。两个进程中同时hold住了DOM信息,在多进程下很难道控制,所以干脆就放在一个进程里了。这个算是chrome的一个小缺陷(firefox也有,ie没有),不过chrome目前正在跟进和优化这里,详情可参考这里。
通过在a标签上添加这个noopener属性,可以将新打开窗口的opner置为空。特点:
var otherWindow= window.open();
otherWindow.opener = null;
other = 'http://newurl';
特点:
特点: