最近公司交付的信息系统中的一个功能,上线后用户一直反馈说卡顿,明明我已经优化了好几轮,在本地速度快的飞起,怎么线上就不行,负责集成测试的同事没有定位到问题的缘由。
我到现场看,发现这个信息系统(这里称B),是挂接在另一个系统(这里称A)里作为子系统,通过链接跳转,它们共享相同的域名,协议,端口。用户在A系统点击链接跳转B系统时,浏览器基于站点策略会将新打开的B系统的标签页与原A系统标签页共用一个进程。我是怎么确定的呢,因为当B系统运行计算密集型功能出现异常时,A和B对应的标签页都崩溃了,若是手动打开标签页输入网址后运行则不会出现上述问题。我打开浏览器任务管理器一看,果真如此,就是共享进程。
A系统本身是一个胖应用,进程内占用了大量资源,如内存,CPU等,而B系统作为一个三维信息系统,同样也是胖应用,也需要很多资源,在与A系统的资源竞争中阻塞了运行。
一般如chrome等浏览器,手动开启一个标签页会启动一个新进程,而针对链接跳转打开标签页时,浏览器在分配进程会遵循如下规则:
相同域名的标签页
默认共享进程:
若两个标签页属于同一站点(协议+域名+端口相同),且通过常规方式打开(如 <a href="..." target="_blank">
未设置 rel="noopener"
),可能会共享同一渲染进程。
例外:
rel="noopener noreferrer"
打开新标签页,浏览器会强制分配独立进程。window.open()
时,若未设置 noopener
,某些浏览器仍可能共享进程。不同域名的标签页
独立进程:
不同域名(或不同协议/端口)的标签页默认分配独立渲染进程,以防止跨站脚本攻击(XSS)和数据泄露。
站点隔离:
现代浏览器(如 Chrome)默认启用该功能,强制不同域名的页面隔离进程,即使它们属于同一主域名下的子域名。
至于问题处理的方式很简单粗暴,在A系统上跳转时,强制将新开启的标签页置于独立进程内而不是共享A系统页面进程。理想很丰满,现实很骨感,因为A是上级开发的系统,我们没有权限修改,想改就得向上申请,所以最后做了一个妥协的方案,在进入B系统前,先判断该标签页是属于共享进程还是独立进程,若前者的话则弹出一个窗口(弹窗),引导用户点击按钮开启独立标签页,然后系统自动把原标签页关闭。
至于为什么选择弹窗引导的方式,因为浏览器不允许使用JS触发新的标签页(这种方式触发称之为弹出式窗口),这个权限默认关闭,当强行用JS触发新标签页时,浏览器的搜索栏会出现一个很小的权限请求窗口,很隐蔽导致用户可能根本没注意到,所以干脆做一个显性的引导。