页面循环和渲染流程
#积累/浏览器原理
先来看看页面渲染完成之后的情况:
渲染进程的主线程一直在循环监听,如果消息队列中存在任务,则按队列顺序依次执行。
消息队列是一种队列数据结构,用来存放要执行的任务,任务包括:HTML解析、CSS解析、JavaScript 执行、样式计算、布局计算、CSS 动画;输入事件(鼠标滚动、点击、移动)、微任务、文件读写、WebSocket、JavaScript 定时器等等。
渲染进程还有IO线程,接收其他进程传来的消息,并push到消息队列中。包括:网络进程的资源加载完成、浏览器进程的鼠标点击事件等。
宏任务和微任务
渲染进程是单线程执行的,可能单个任务执行时间过长,不能满足实时性的需求,如监听 DOM 变化并及时地做出响应。因此出现了微任务。
消息队列中的任务是宏任务,每个宏任务都关联了一个微任务队列,微任务队列会在宏任务结束之前一直循环执行。在微任务执行过程中产生的新的微任务,也会在当前宏任务中被执行完成。
产生微任务的情况:
使用 MutationObserver 监控某个 DOM 节点,节点的任务变更都会因此产生微任务;
使用Promise,调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务。
渲染流程
HTML、CSS和JavaScript文件是如何产生视觉页面的?
渲染流程包括的子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。
- 构建DOM树/DOM
将HTML转换为浏览器能够理解的结构——DOM树(document) - 样式计算/Style
将CSS转换为浏览器能够理解的结构:styleSheets(document.styleSheets);
转换样式表中的属性值,使其标准化,例如em转换为px,green转换为rgb;
计算出DOM树中每个节点的具体样式(继承和样式层叠) - 布局/Layout
构建布局树,包括DOM 树中可见元素;
计算DOM节点的布局信息,保持在布局树中。 - 分层/Layer
渲染引擎需要为特定的节点生成专用的图层,并生成一棵对应的图层树。
满足什么条件会创建新的图层? - 拥有层叠上下文属性的元素会被提升为单独的一层,包括position、z-index、filter、opacity等
- 需要剪裁(clip)的地方也会被创建为图层,例如overflow的内容元素
- 绘制/Paint
渲染引擎会对图层树中的每个图层生成绘制列表,并提交给合成线程 - 栅格化操作/Raster
合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。 - 合成和显示
合成线程发送绘制图块命令 DrawQuad 给浏览器进程;
浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。