页面循环和渲染流程

#积累/浏览器原理

先来看看页面渲染完成之后的情况:
渲染进程的主线程一直在循环监听,如果消息队列中存在任务,则按队列顺序依次执行。
消息队列是一种队列数据结构,用来存放要执行的任务,任务包括:HTML解析、CSS解析、JavaScript 执行、样式计算、布局计算、CSS 动画;输入事件(鼠标滚动、点击、移动)、微任务、文件读写、WebSocket、JavaScript 定时器等等。
渲染进程还有IO线程,接收其他进程传来的消息,并push到消息队列中。包括:网络进程的资源加载完成、浏览器进程的鼠标点击事件等。

宏任务和微任务

渲染进程是单线程执行的,可能单个任务执行时间过长,不能满足实时性的需求,如监听 DOM 变化并及时地做出响应。因此出现了微任务。
消息队列中的任务是宏任务,每个宏任务都关联了一个微任务队列,微任务队列会在宏任务结束之前一直循环执行。在微任务执行过程中产生的新的微任务,也会在当前宏任务中被执行完成。
产生微任务的情况:
使用 MutationObserver 监控某个 DOM 节点,节点的任务变更都会因此产生微任务;
使用Promise,调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务。

渲染流程

HTML、CSS和JavaScript文件是如何产生视觉页面的?

渲染流程包括的子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。

  1. 构建DOM树/DOM
    将HTML转换为浏览器能够理解的结构——DOM树(document)
  2. 样式计算/Style
    将CSS转换为浏览器能够理解的结构:styleSheets(document.styleSheets);
    转换样式表中的属性值,使其标准化,例如em转换为px,green转换为rgb;
    计算出DOM树中每个节点的具体样式(继承和样式层叠)
  3. 布局/Layout
    构建布局树,包括DOM 树中可见元素;
    计算DOM节点的布局信息,保持在布局树中。
  4. 分层/Layer
    渲染引擎需要为特定的节点生成专用的图层,并生成一棵对应的图层树
    满足什么条件会创建新的图层?
  5. 拥有层叠上下文属性的元素会被提升为单独的一层,包括position、z-index、filter、opacity等
  6. 需要剪裁(clip)的地方也会被创建为图层,例如overflow的内容元素
  7. 绘制/Paint
    渲染引擎会对图层树中的每个图层生成绘制列表,并提交给合成线程
  8. 栅格化操作/Raster
    合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图
  9. 合成和显示
    合成线程发送绘制图块命令 DrawQuad 给浏览器进程;
    浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。