谷歌浏览器新开页面进程问题
开发项目过程中,会遇到点击页面上某个东西,要在新窗口中打开一个页面的需求。如果你认为是简简单单的打开一个新窗口,那就会掉进谷歌浏览器的坑里了。
场景:在A页面,点击按钮,新开窗口跳转到该项目的B页面,如果B页面的请求尚未结束,直接关闭B页面,此时A页面会卡死。
原因:谷歌浏览器在给新开窗口分配进程时,看是否同源,非同源页面会单独分配一个新进程,而同源页面只会分配一个相同的新进程。在上述场景中,A,B页面同源,所以谷歌浏览器只会分配一个进程,这就导致B页面在请求未结束时就关闭,A页面会卡死。
下面来看一下不同方式打开新页面的浏览器分配进程情况。
一、查看谷歌浏览器的进程
1、找到浏览器的自定义及控制图标
2、点击找到更多工具
3、点击更多工具并点击任务管理器
4、进程如下:
二、使用a标签打开新窗口
1、使用a标签打开非同源窗口
<a href="https://www.baidu.com/" target="_blank">新开窗口跳转到百度</a> <a href="https://www.cnblogs.com/" target="_blank">新开窗口跳转到博客园</a>
使用a标签分别打开了百度以及博客园首页,这两个非同源,所以浏览器会分配两个新进程。如下图:
2、使用a标签打开同源窗口
<a href="https://juejin.im/" target="_blank">新开窗口掘金</a> <a href="https://juejin.im/" target="_blank">新开窗口掘金</a>
使用a标签打开掘金首页,这两个同源,所以浏览器只会分配一个新进程。如下图:
三、使用window.open打开新窗口
使用window.open打开新窗口与a标签打开结果相同
<Button onClick={() => window.open('https://www.csdn.net/')}>window.open跳转到CSDN</Button> <Button onClick={() => window.open('https://www.csdn.net/')}>window.open跳转到CSDN(同源)</Button> <Button onClick={() => window.open('https://www.jianshu.com/')}>window.open跳转到简书(非同源)</Button>
点击3个Button,打开3个新窗口,只分配了2个进程,CSND同源,共用一个进程,简书单独一个进程。
四、如何解决同源同一进程
一般来说,新开窗口肯定是想新开一个进程,这样两边页面不会受到影响。要想同源不同进程,就需要将新创建的标签页的 opener 属性设置为 null,表示在单独的进程中运行新标签页,这样浏览器就会给每一个新开窗口分配一个进程。
1、window.open设置opener为null不会起作用
const handleClick = () => { let otherWindow: any = window.open(); otherWindow.opener = null; otherWindow.location = 'https://www.baidu.com/'; } <Button onClick={handleClick}>window.open设置opener跳转到百度</Button> <Button onClick={handleClick}>window.open设置opener跳转到百度</Button>
将opener设置为null之后,再打开新窗口。结果浏览器并没有单独分配进程,还是同源分配一个进程。
这就要使用a标签代替window.open来解决
2、a标签添加rel="noopener noreferrer"解决同源同进程
<a href="https://www.baidu.com/" target="_blank" rel="noopener noreferrer">新开窗口添加rel跳转到百度</a> <a href="https://www.baidu.com/" target="_blank" rel="noopener noreferrer">新开窗口添加rel跳
转到百度</a>
a标签添加rel="noopener noreferrer"就相当于将新窗口的opener置为null,此时浏览器会给新开窗口都单独分配一个进程。
五、项目中使用
创建a标签并触发方法打开新页面
let a = document.createElement('a'); //创建a标签 a.setAttribute('href', url); //url即为需要打开的新页面的url a.setAttribute('target', '_blank'); //_blank新窗口打开 a.setAttribute('rel', 'noopener noreferrer'); //添加rel document.body.appendChild(a); a.click(); //触发click
这样每次打开一个新窗口时,就会创建一个新的进程。