22

浏览器工作原理学习笔记

 4 years ago
source link: https://blog.callmewhy.com/post/liu-lan-qi-gong-zuo-yuan-li-xue-xi-bi-ji/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

多进程

单进程问题

  • 不稳定,插件崩溃浏览器就崩溃
  • 不流畅,脚本执行会让页面卡顿,内存泄漏也会导致浏览器变慢
  • 不安全,恶意插件和恶意脚本容易获取系统权限作恶

多进程优点

  • 进程隔离,插件或者页面崩溃不会导致其他页面崩溃
  • 页面隔离,即使 JS 阻塞了渲染进程,影响到的也只是当前的渲染页面,而并不会影响浏览器和其他页面,其他页面的脚本是运行在它们自己的渲染进程中的,浏览器也可以正常使用。
  • 通过安全沙盒解决安全问题

五个常见进程

rel="noopener noreferrer"

渲染

浏览器渲染机制

  • DOM:渲染引擎解析 HTML 文档,构建 DOM Tree
  • Computed Style:解析对应的 CSS 样式信息,生成 document.styleSheets,计算 DOM 样式
  • 布局(reflow/layout):计算布局信息,生成布局树 LayoutTree
  • 分层(layer):对布局树进行分层。满足以下条件之一就会提升为单独图层:有层叠上下文属性,或者需要裁剪(超出/滚动)。
  • 绘制(repaint/paint):遍历渲染树,绘制每个节点,把每一个元素对应的盒变成位图。
    mq6Rvyq.png!web

重排、重绘、合成

  • 重排(reflow):当渲染树中的部分因为元素的尺寸、布局、隐藏等改变而需要重新构建。触发条件:页面渲染初始化(无法避免)、添加或删除 DOM、DOM 位置或尺寸的改变、浏览器窗口尺寸的变化、填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变。
  • 重绘(repaint):改变元素外观所触发的行为,浏览器会根据元素的新属性重新绘制,省去了布局和分层阶段。比如,仅修改 DOM 元素的字体颜色。
  • 合成:既不改布局也不需要绘制,比如 CSS transform 动画,避开重排与重绘阶段,在非主线程上执行合成动画操作。
  • display: none; 会发生 reflow,而 visibility: hidden; 只会触发 repaint

如何避免重排重绘

  • 通过 class 批量修改样式
  • 使用离线 DOM 或者 documentFragment
  • 避免使用 table 布局
  • 对类似 window resize 这样的事件做 debounce
  • 对 dom 属性的读写分离

JS 和 CSS 阻塞

  • JS:会先下载并执行,再继续渲染,也就是说,下载和执行,都会阻塞 DOM 解析,因为 JS 可能存在 DOM 操作
  • CSS:正常不会阻塞 DOM 解析,但是遇到 script 标签会触发渲染,会等到 CSS 下载完成再继续执行,这种情况下会阻塞 DOM 解析。

五个常驻线程

JS Runtime 是单线程,但是浏览器提供多线程环境

  • GUI 渲染线程:负责解析HTML,CSS,构建DOM树,布局和绘制,与 JS 引擎线程互斥
  • JS 引擎线程:负责处理 JS 脚本,执行会阻塞渲染线程
  • 定时器触发线程:负责执行定时器一类函数的进程,如 setTimeout、setInterval。主线程执行代码遇到计时器时,会将计时器交给该线程处理,当计时完毕之后,定时器线程会将计时完毕后的事件加入到事件队列的尾部,等待 JS 引擎线程的执行
  • 事件触发线程:主要负责将准备好执行的事件交给 JS 引擎线程执行,如计时器计时完毕后的事件,AJAX 请求成功返回并触发的回调函数和用户触发点击事件时,事件触发线程会将回调函数加入到任务队列的尾部,等待 JS 引擎线程的执行
  • 异步 HTTP 请求线程:当主线程依次执行代码时,遇到异步请求,会将函数交给改线程处理,当监听状态码变更时,如果有回调函数,会将回调函数加入到任务队列的尾部,等待 JS 引擎线程的执行

Event Loop

主线程从任务队列读取事件这个过程,是循环不断的,称之为 Event Loop。

  • 执行栈里清空了,才会从任务队列中取任务,浏览器不止一个任务队列(Task Queue 和 Microtask Queue)
  • setTimeout 是浏览器行为,和 DOM 事件一样
  • 宏观任务一个一个执行,微任务一批一批执行

异步任务有两种:

  • 宏任务(Macrotask):宿主发起的任务,包括整体代码 script,setTimeout,setInterval、setImmediate、I/O操作、UI rendering
  • 微任务(Microtask):JavaScript 引擎发起的任务,process.nextTick, Promises, Object.observe, MutationObserver
VBniAzq.jpg!web

事件模型

DOM 事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播(propagation)。

这种传播分成三个阶段:

  • 捕获阶段:事件从 window 对象自上而下向目标节点传播的阶段
  • 目标阶段:真正的目标节点正在处理事件的阶段
  • 冒泡阶段:事件从目标节点自下而上向 window 对象传播的阶段

在实际监听事件时,可以这样使用冒泡和捕获机制:默认使用冒泡模式;当开发组件时,遇到需要父元素控制子元素的行为,可以使用捕获机制。

事件代理

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,通过 event.target 来判断。这种方法叫做事件的代理(delegation)。

优点:

  • 减少内存消耗,提高性能
  • 方便动态绑定事件

参考资料


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK