Shared Event-loop for Same-Origin Windows(译)
一 前言在翻译这篇文章Tasks,microtasks,queues and schedules时,有一个不懂之处:"All windows on the same origin share an event loop as they can synchronously communicate."Google之后就有了这篇文章。 我们将一组用相互用script连接的Tabs称为一个浏览实例,它对应于HTML5规范中的“相关的浏览上下文单元”。 该组由一个选项卡和任何其他使用Javascript代码打开的选项卡组成。 例如有ABC三个页面,在A中执行window.open(B),那么AB就是同源,B又打开了C,则ABC就是同源。 二 正文原文地址:http://hassansin.github.io/sh... 我最近看到一篇文章上说:“来自同一个源的所有窗口共享一个事件循环,它们也可以同步通信。” 照它这么说 -- 如果我在浏览器上打开了多个Tab(因为选项卡与现代浏览器中的窗口基本相同),Tab来自同一主机的不同页面,它们全都将呈现在单个线程中。 但是这没根本不可能吧,因为Chrome在其自己的进程中运行每个Tab。 他们无法共享相同的事件循环。 文章说法有待考证。 谷歌浏览器进程的模型使用chrome任务管理器的快速测试证明我是正确的。每个具有来自相同域的Tab确实是在单独的进程中运行。 但是当我在Chrome任务管理器进程中进行挖掘时,我注意到一些Tab是在相同进程ID下运行的。 例如: Tabs甚至不是来自同一个域却在同一个进程里面。 所以这里发生了什么? 谷歌快速搜索后,事实证明,Chrome有一个复杂的流程模型:chromium.org/developers/design-documents/process-models。 默认情况下,Chrome使用process-per-site-instance模型,即: Chromium会为用户访问的每个站点实例创建一个渲染器进程。 这确保了来自不同站点的页面被独立渲染,并且对同一站点的单独访问也彼此隔离。 因此,一个站点的一个实例中的失败(例如渲染器崩溃)或资源占用率过高不会影响浏览器的其余部分。 **该模型基于内容的源和相互执行脚本的选项卡之间的关系。** 因此,两个选项卡可能会显示在任务管理器的同一个进程中,而当在已经打开的一个页面的选项卡中导航到跨站页面时,可能会切换选项卡的渲染器进程。 但事实上,我认为实际情况比上述内容更复杂。 不管那些了,我迫切地想测试一下这些Tab是否真的共享相同的Event Loop。 所以我写了一个长时间运行的同步任务。 你猜怎么了! 这只是一个空循环: function longrunning(){ for (let i=0; i<10000000000; i++); } 然后,我需要将其注入到这些tabs-per-process的其中一个中去。 有一个很好的扩展称为 窗口之间同步通信回到我刚才讨论的第一篇文章。 它也提到这些窗口还可以同步进行相互通信。 所以这些Tab必须以某种方式相互连接。 从关于Chrome进程模型的文章: 我们将一组用相互用script连接的Tabs称为一个浏览实例,它对应于HTML5规范中的“相关的浏览上下文单元”。 该组由一个选项卡和任何其他使用Javascript代码打开的选项卡组成。 这些选项卡必须在同一个进程中呈现,以允许在它们之间进行Javascript调用(最常见的是来自同一源的页面之间)。 好吧,这意味着我们需要使用JavaScript打开它们,才能连接窗口。 实际上有几种方法可以在javascript中执行此操作。 使用 演示在这里demo。 你需要让浏览器允许弹出窗口才能看到效果。 top.html: <html> <head> <title>Top window</title> <script> function longrunning(){ for(let i=0;i<2000000000;i++); } let t0 let t1 const elapsedTime = () => { if(!t0) { t0 = performance.now() t1 = t0 } else { t1 = performance.now() } return ((t1-t0)/1000).toFixed(2) } window.parentLogger = (str) => { console.log("[%s] TOP: %s",elapsedTime(),str) } window.childLogger = (str) => { console.log("[%s] CHILD: %s",str) } parentLogger('before opening popup') const popup = window.open('child.html'); // var popup = window.open('/child.html','','noopener=true'); if(popup) { parentLogger(`after popup opened,popup window url: ${popup.location.href}`) } parentLogger('starting long synchronous process. This will prevent loading and parsing of popup window') longrunning(); parentLogger('finished long synchronous process.') parentLogger('adding 1s timeout.') setTimeout(function(){ parentLogger('timed out') },1000) </script> </head> <body></body> </html> child.html: <html> <head> <title>Child window</title> <script> function longrunning(){ for(let i=0;i<2000000000;i++); } window.addEventListener('DOMContentLoaded',e => window.opener.childLogger(`popup initial html loaded,popup window url: ${window.location.href}`)) window.opener.childLogger('starting long synchronous process inside popup window. This will prevent the event loop in top window') longrunning() window.opener.childLogger('finished long synchronous process inside popup window.') // window.close() </script> </head> <body></body> </html> 不过,这里有top.html中控制台的输出: [0.00] TOP: before opening popup [0.01] TOP: after popup opened,popup window url: about:blank [0.01] TOP: starting long synchronous process. This will prevent loading and parsing of popup window [4.93] TOP: finished long synchronous process. [4.93] TOP: adding 1s timeout. [5.82] CHILD: starting long synchronous process inside popup window. This will prevent the event loop in top window [10.79] CHILD: finished long synchronous process inside popup window. [11.15] CHILD: popup initial html loaded,popup window url: http://localhost:4000/assets/chrome-process-models/child.html [11.18] TOP: timed out 你可以在每个事件的方括号中查看以秒计的总时间。
所以从弹出窗口中加载内容的时间点以及在顶部窗口中触发setTimeout回调的时间点可以清楚地看到,它们都共享相同的事件循环。 那么我们如何让同源窗口在它自己的进程中运行而不影响彼此的事件循环呢? 事实证明,我们可以在 所有这些行为在不同的浏览器中可能会有所不同。 这实际上都是特定于浏览器的实现。 我们甚至可以在Chrome中传递不同的标志并选择不同的过程模型。 三 后记这篇文章给出了最终答案:来自同一个源的Tabs共享相同的事件循环。 补充一:同一进程打开chrome的任务管理,可以看到任务情况。 window.open('https://segmentfault.com/a/1190000014833359'); 打开了一个新的Tab,但是: 在同一个进程里。 window.open('https://www.baidu.com'); 又打开了一个新的Tab, 嗯,还是同一个进程。 补充二:如何优化(编辑:莱芜站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- Windows上Jenkins的git插件不使用带子模块的凭据
- windows下mysql主从复制配置
- Windows调试器路线图
- wcf – 有关替换Microsoft .NET的Web服务增强功能(WSE)3.0的
- Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF
- Windows Azure SDK for C
- windows-phone-8 – 适用于Windows Phone 8的企业应用程序分
- windows-services – 监控单个窗口服务的性能
- 标签为Windows的SSH工具?
- windows – CFileDialog :: OnInitDialog()不调用
- 如何在Windows PowerShell中进行屏幕截图?
- Win10 将应用程序exe放到开始屏幕
- windows-ce – Windows CE的应用程序开发
- libglog.dll CMake 在Windows上编译、应用glog
- .net – “可点击”文本框?
- macos – 在Windows上使用Tycho构建的Eclipse RC
- 如何在Windows 7上安装PHP 7的MongoDB驱动程序?
- windows – 如何从命令行启动一个ruby脚本只是它
- Windows上Jenkins的git插件不使用带子模块的凭据
- ms-office – Microsoft Office 2010功能区自定义