本文主要简单聊聊 lit-html 的核心原理
在之前,我了解到的只有 React 的虚拟 dom。
"每次渲染生成新树 -> 对比两棵树 -> 找出差异 -> 更新真实 dom"
但是, lit-html 走了一条完全不同的路。没有虚拟 dom,不进行复杂的树对比,却能够实现极高的性能
# 核心一:ES6 的 -- 标签模板字面量
ES6 的一个新特性,标签模板字面量。
当写出如下代码时
const name = "ay"; | |
html`<h1>Hello, ${name}</h1>`; |
html 其实是一个函数。浏览器在处理这段代码时,会把模板拆解成两部分传给这个函数
- Strings:
["<h1>Hello, ", "</h1>"]; - Values:
["ay"];
关键:无论这个组件重新渲染多少次,静态字符串数组在内存中时同一个引用,永远不变
lit-html 区分出了静态字符串和动态数据,只处理后者
# 核心二:原生 <template> 元素
有了静态字符串,就可以用原生的 <template> 元素来存储这些字符串<template> 是 HTML 标准中的一个特殊标签。它里面的内容会被浏览器解析,但不会渲染,也不会执行脚本。就类似于一个模板
# 第一次渲染流程
假设有如下代码
let count = 0; | |
const renderTemplate = () => html`<div>Count: ${count}</div>`; |
第一次调用 render 时,lit-html 会做如下几步
- 预处理与占位
lit-html 拿到静态字符串,他会把变量的位置用一个特殊的占位符填上
生成的模板为<template><div>Count: </div>
</template> - 缓存
lit-html 会用那个静态字符串数组作为 key,缓存这个<template>元素
下次渲染时就不需要解析 HTML 字符串了 - 克隆与寻址
现在要显示内容。lit-html 会把<template>的内容克隆一份,然后通过TreeWalker来遍历这个克隆后的 DOM 树,找到所有的占位符 - 创建 Parts
当找到占位符时,它会创建一个Part对象,这个对象手里拿着对这个具体 DOM 节点的直接引用
此时,他就不需要去 DOM 树中找节点,Part对象就直达节点
# 核心三:精确更新
当状态改变, count 变成 1,再次调用 render
- 识别:
html函数运行,检查静态字符串数组是否变化 - 跳过:完全跳过 HTML 解析、DOM 创建、DOM 遍历
- 对比数据
- 直达更新:找到这个位置的
Part对象,直接更新节点的内容
# 总结
- 它利用 ES6 模板字符串 来区分静态和动态
- 它利用 HTML
<template>来高效克隆 - 它利用 闭包和对象引用 (Parts) 来避免昂贵的 DOM 查询
就好比一个有着明确目标的修理工,他会直达在 DOM 树中需要修复的地方,然后直接对这个节点进行操作,而不是去遍历整个树