DOM
解析器不是等文档加载实现才解析的,而是边加载边解析。
网络过程依据收到的 content-type=text/html
判断是 html
类型,为该申请创立一个渲染过程,渲染过程筹备好后会在网络过程和渲染过程中建设一个共享数据的管道,网络过程按收到的字节流像水一样的倒进这个管道,渲染过程的 html
解析器会动静接管字节流将其解析为 DOM
。
字节流Bytes
——> 分词器Tokens
——> 生成节点Node
——>DOM
- 通过分词器将字节流转换成
Token
,分为TagToken(StartTag、EndTag)
和文本Token
- 将
Token
解析为DOM
节点,增加到DOM
树,Html
中有一个Token
栈构造,第一步中生成的Token
都会进入这个栈中。如果是StartTag
,Html
解析器会为Token
创立一个Dom
节点,而后退出到DOM
树中。如果是文本Token
,会生成一个文本节点退出DOM
树中,不必压入栈。如果是EndTag
,Html
会查看栈顶元素有没有它的StartTag
,有就从栈顶弹出,示意该元素解析实现。
如果在 2 段 div
中插入 script
,解析到(script
) 会暂停 DOM
解析,JS
脚本实现后,Html
解析器复原继续执行。渲染过程接管字节流时,也会开启一个预解析线程,遇到 JS
或CSS
文件预解析线程会提前下载这些数据。申请 Html
到构建 DOM
之间有一段闲暇工夫,构建 DOM
树之后 css
未下载完之前也会有一段闲暇工夫,可能会有白屏。
<html>
<head><link href="them.css" rel="stylesheet" /></head>
<body>
<div>segmentfault.com</div>
<script src="foo.js"></script>
<div> 思否 </div>
</body>
</html>
解析 Html
、下载CSS
、下载JS
、生成CSSOM
、执行JS
、生成布局树、绘制页面。
次要空白:下载 CSS
、下载JS
、执行JS
、html
下载
策略:1. 内联 JS
,css
移除下载。2. 缩小文件大小、webpack
移除正文,压缩、JS
标 defer
或async
,css
合成
优化:
- 加载阶段:网络,
JS
脚本,图片,音频,视频文件不会阻塞页面首次渲染。JS
,html
,css
文件会阻塞。构建DOM
须要Html
和JS
,构建渲染树须要CSS
。
(1). 要害资源个数:数据越多,首次加载工夫越长。1. 改成内联。2.JS
没有DOM
或CSS
操作,加defer
或async
。css
加madio
。
(2). 资源大小:资源越小,下载工夫越短。压缩css
,js
资源。移除正文。
(3).RTT
数量:传输分包,小于14k
只用 1 个RTT
。RTT
次数越多,申请工夫越长,缩小个数或大小。CDN
缩小时长。 - 交互阶段:
JS
脚本,渲染过程渲染帧的速度。
(1). 缩小JS
脚本执行工夫:1. 执行函数合成多个工作。2.web workers
。不要霸占主线程太久。
(2). 防止强制同步布局:通过DOM
接口,增加删除元素,须要从新计算款式和布局。批改DOM
前查问相干值。同步布局:JS
强制将计算款式和布局操作提前到当前任务中。如加个元素,而后获取此元素高度,获取就要布局后能力获取。
(3). 防止布局抖动:一次JS
执行中,屡次强布局和抖动。如for
循环中,一直读取属性值,每次读都要进行计算款式和布局。不要在批改DOM
时再去查相干值。
(4). 正当利用css
合成动画,css
合成动画在合成线程上执行。不受主线程限度,尽量用css
合成动画。
(5). 防止频繁垃圾回收,垃圾回收时会占用主线程。优化存储构造,防止小颗粒对象的产生。
DOM
的缺点:DOM
提供了一组 JS
接口来遍历或批改节点。JS
操作 DOM
会影响到整个渲染流水线。如 document.body.appendChild(node)
,往body
节点增加一个元素,首先渲染引擎将 node
增加到 body
之上,而后触发款式计算、布局、绘制、栅格化。布局和布局抖动问题,会大大降低渲染效率。
虚构 DOM
通过 JS
和根底数据创立虚构 DOM
,由虚构DOM
创立出实在 DOM
树,再触发渲染流水线输入屏幕。如果产生扭转就依据新数据创立新的虚构 DOM
,而后比拟 2 颗虚构DOM
找出变动,再把所有变动一次性从新更新实在 DOM
树上,更新渲染流水线,生成新页面。react
之前的递归算法比拟多的话会占主线程比拟久,造成卡页面。Fiber
又叫协程,执行算法的时候让出主线程,解决占用工夫久的问题。双缓存,先将计算结果放在另一个缓存区,全副计算完再把后果利用到 DOM
上,缩小不必要更新。
渲染引擎会将所有的 css
内容解析为 CSSOM
。生成布局树的时候,会在CSSOM
中为布局树元素查找款式,2 个雷同标签显示的成果会是一样的,渲染引擎不会为他们独自设置款式。css
会影响到 DOM
中其它同样标签的款式。JS
也能在任何中央批改DOM
。是妨碍组件化的 2 个因素。
webComponent
是一套技术的组合,Custom elements
(自定义元素)、shadow DOM
(影子 DOM
)、Html templates
(Html
模板)。webComponent
提供了对部分视图封装能力,能够让 DOM
、CSSOM
、JS
运行在部分环境,不会影响到全局。
微服务框架 qiankun
就是用的这个。
新建一个组件:1. 定义模板。2. 定义外部 css
款式。3. 定义 JS
行为
<!DOCTYPE html>
<html>
<body>
<template id="template">
<style>
p{
background-color: brown;
color: cornsilk;
}
div{
width: 200px;
background-color: bisque;
}
</style>
<div>
<p>text1</p>
<p>text2</p>
</div>
<script>
function foo(){console.log('inner log')
}
</script>
</template>
<script>
class ShadowDomTemplate extends HTMLElement{constructor(){super();
// 获取组件模板
const content=document.querySelector('#template').content;
// 创立影子 DOM 节点
const shadowDom=this.attachShadow({mode:'open'});
// 将模板增加到影子 DOM 上
shadowDom.appendChild(content.cloneNode(true));
}
}
customElements.define('temp-component',ShadowDomTemplate);
</script>
<temp-component></temp-component>
</body>
</html>
渲染出:
<!DOCTYPE html>
<html>
<head></head>
<body>
<template id="template">
#document-fragment
</template>
<script></script>
<temp-component>
#shadow-root(open)
<style>...</style>
<div>...</div>
</temp-component>
</body>
</html>
影子 DOM
元素对网页不可见。
影子 DOM
的作用将模板中内容与全局 DOM
和css
进行隔离,实现元素和款式私有化。能够把影子 DOM
看成一个作用域,外部款式和元素不会影响全局。全局下要拜访影子内款式元素,通过约定好的接口,互不影响。
只通过影子 DOM
隔离 css
和DOM
,但不会隔离 JS
。JS
能够被拜访,渲染引擎判断 temp-component
下shadow-root
,如是影子 DOM
会跳过,款式也只会从外部找。