chrome官方解释在导航栏输入url敲下回车后发生了什么?

这是来自谷歌官方博客: inside modern browser 的四篇系列文章,也有人作了全文翻译,参见承香墨影。本文可看做一个abstract,对全文进行了重点摘要,以期读完后对chrome浏览器的体系结构,处理机制有整体的了解。有个经典的前端面试问题:在导航栏输入url敲下回车后发生了什么?本文可以看做一个比较全面、深入一点的回答。

浏览器体系结构

  • CPU 一个接一个地处理多项任务
  • GPU 同时、跨内核处理多个简单任务

开启application时,机器的物理硬件在最底层,中间是操作系统,最上层才是应用本身。

浏览器没有一定之规。有的是单进程多线程,有的是多进程,一个进程有少量的多个线程IPC。

进程 功能
Browser controls ‘chrome’ part of the app and privileged parts such as network requests and file access
Renderer anything inside of the tab where a website is displayed
Plugin any plugins used by the web like flash
GPU Handles GPU tasks in isolation from other processes. It is separated into different process because GPUs handles requests from multiple apps and draw them in the same surface.
  • 出于安全和沙箱考虑,每个tab有独立的renderer process
  • 因为每个进程有独立的内存空间,这会造成一定的资源浪费(can’t share common infrasructure like v8), chrome限制了它可以启动的进程数量。如果达到了限制,则会把多个tab上那些同源的网页合并到一个进程中。
  • chrome 正在做的事情是,把浏https://www.cnblogs.com/peida/archive/2013/03/05/2943698.html览器程序的每个部分作为一项可拆分的服务。当 Chrome 在强大的硬件上运行时,它可能会将每个服务拆分为不同的进程,从而提供更高的稳定性,但如果它位于资源约束的设备上,Chrome 会将服务整合到一个进程中,从而节省内存占用。
  • 整合进程以节省资源的策略已经被用于其他平台,如andriod上。

在这里插入图片描述

每个frame有独立渲染进程,站点隔离

导航过程

tab之外的一切都是浏览器进程控制。浏览器进程包括:

线程 功能
UI线程 绘制按钮和输入框
网络线程 处理网络请求和堆栈
存储线程 控制对文件的读取

输入url是由UI线程控制的

  1. 处理输入: isSearchInput? to search engine : to the site you requested
  2. 开始导航: UI线程控制loading spinner, 网络线程建立连接
  3. 读取res:网络线程,response’s Content-Type header不一定可信,嗅探MIME TYPE判断响应体的格式,安全检查,CORB。
  • html ----> 交给renderer进程渲染
  • zip ----> 下载管理器download
  1. UI线程找到一个渲染进程,优化:在步骤2的同时,UI线程主动去找或者开启一个渲染进程。
  2. commit navigation:浏览器进程和渲染进程IPC,完成导航。地址栏、session 历史更新。
    IPC between the browser and the renderer process when rendering page
    导航commit后,渲染进程结束渲染,所有onload事件都触发、执行完毕后,IPC告诉浏览器进程,UI线程停止loading spinner

导航到别的站点前,会处理所有的beforeunload事件
新导航会新开一个渲染进程,老的渲染新城处理unload事件等

  • service worker:在渲染进程中运行,从缓存中加载资源
  • 导航预加载:加载资源和开启service worker同时进行

渲染进程

渲染进程包括:

扫描二维码关注公众号,回复: 3826382 查看本文章
  • 主线程
  • service worker/web worker 线程
  • compositor thread
  • raster thread

link, img 会preload, 但script 会阻塞html继续解析,直至script被执行完

  • async/defer

  • js module

  • < link rel='proload >
  • 先计算每个node 的样式,主线程再算出整体的布局树,包括x,y 坐标和盒模型的大小

  • layout tree 类似dom tree,但只包含页面可见部分的结构。display: none 会被忽略。visibility: hidden不会,伪元素如果有content也不会。

  • 这之后要决定绘制的顺序(层次)。z-index。主线程会生成paint records,一条条记录绘制的顺序。

  • repaint 很费cpu。 大多数浏览器刷新页面的速度是60次/秒。最佳实践是把js操作分成小粒度,用requestAnimationFrame()来调用。

  • 组合。turn all above information into pixels(rasterizing/位图化)。

  • css: will-change 提醒浏览器该元素要分成单独的层。

  • compositor frame 被提交给浏览器进程。如果滚动,compositor thread 会生成一个新的compositor frame 给GPU。

componsitor处理输入交互

对浏览器而言,任何用户的gesture都属于input

  • 浏览器进程先获取到gesture, 再把event的类型和坐标发给渲染进程
  • 渲染进程找到事件的目标,and run attached event listeners.
  • compositor thread marks ‘non-fast scrollable region’, a region of the page that has event handlers attached. 如果事件在该区域发生了,compositor thread就发送input event 给主线程。如果是在其他区域有input, compositor thread 继续组装新的frame,不用等main thread.
  • 事件委托可能会不必要地扩大了non-fast scrollable region, 造成平滑滚动效果被减弱。想要暗示浏览器的组装器继续组装而不是等待主线程,可以这么做:
// 但实际上,chrome会报错说can't prevent default inside passive...建议直接用css: touch-action来改。
document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});
  • 离散的事件立即分发,连续事件如wheel, mousewheel, mousemove, pointermove, touchmove 会延迟分发,卡在requestAnimationFrame的每一帧变换上。(input事件的传达速度多在60fps以上,这是一种优化)
  • getCoalescedEvents 来获取这些被合并的事件
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
})

猜你喜欢

转载自blog.csdn.net/github_36487770/article/details/82910015
今日推荐