万万没想到【window.open】导致了页面卡顿

818 阅读2分钟

问题

最近在排查打开多个网页时,文件预览卡顿的问题,意外地发现了一个window.open的问题

  • 文件预览流程是这样的,点击文件然后会跳转到新窗口打开
  • 在工业上,一般会打开很多的文件,文件体积又大(经常性的几十兆,上百兆)
  • 当打开很多图纸之后,会隐约感觉到页面有点点卡顿
  • 打开十几个tag,卡顿也能理解,但是奇怪的是当关闭掉这些打开的零件之后,卡顿还是没有好转
  • ....

一顿疯狂排查之后,发现竟然是浏览器内存没有被释放的原因:

可以看到,左边有一个蓝色的竖线,表示这几个页面是关联起来的

因为下面几个页面是用window.open的方式打开的,虽然是打开了新的tag页面,但是它们其实是和父级tag页面是共用一个进程

所以即使关闭了这些新打开的tag,只要父级tag不关闭,内存其实不会被释放掉的;

而且经常性地不会关闭主tag页面,这就导致了内存迟迟没有被释放,页面也就变得卡顿了

原因

默认情况下chrome会为每一个tab创建一个渲染进程,比如:

  1. 当我们在url上输入一个新的url
  2. 通过a标签打开新页面时

都会创建一个新的进程,分配独立运行的内存空间

但是,通过window.open()的方式打开新页面,如果打开新页面的站点与当前页面的站点属于 “同一站点” ,会被分配到同一个渲染进程,这就导致多个tag页面共享一个进程

同一站点:协议 + 根域名 相同

window对象中有一个opener属性,指向的是创建该窗口的window对象的引用

当使用window.open打开新页面的时候,window.opener指向的是当前的tag页面(父级tag

所以这种方式跳转的页面,可以通过opener属性访问父级页面的全局方法和数据

使用a标签或者输入url的方式打开新页面,window.opener指向为null,说明是独立开启的,没有任何页面依赖,那么就会新建渲染进程,分配内存空间

解决

问题找到了,就好解决了,把window.open替换掉

a标签代替是个不错的主意:

export const openwindow = (url: string) => {
  const link = document.createElement('a')
  link.href = url
	link.target = '_blank'
  document.body.appendChild( link)
  link.click()
  document.body.removeChild(link)
}