Author:霍春阳(HcySunYang)
在这本书问世之前,我就已经看过霍春阳的Vue.js 3源码解读,当时就很欣赏他对技术细节的专注和投入。后来春阳为Vue.js 3提交了大量补丁,修复了一些非常深层的渲染更新bug,为Vue.js 3做出了很多贡献,成为了官方团队成员。春阳对Vue.js 3源码的理解来自参与源码的维护中,这是深入理解开源项目最有难度但也最有效的途径。也因此,这本书对Vue.js 3技术细节的分析非常可靠,对于需要深入理解Vue.js 3的用户会有很大的帮助。 春阳对Vue.js的高层设计思想的理解也非常精准,并且在框架的设计权衡层面有自己的深入思考。这可能是这本书最不同于市面上其他 纯粹的“源码分析”类图书的地方:它从高层的设计角度探讨框架需要关注的问题,从而帮助读者更好地理解一些具体的实现为何要做出这样的选择。 前端是一个变化很快的领域,新的技术不断出现,Vue.js本身也在不断地进化,我们还会继续探索更优化的实现细节。但即使抛开具体 的实现,这本书也可以作为现代前端框架设计的一个非常有价值的参考。 尤雨溪,Vue.js作者
Tags
Support Statistics
¥.00 ·
0times
Text Preview (First 20 pages)
Registered users can read the full content for free
Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.
Page
1
(This page has no text content)
Page
2
版权信息 书名:Vue.js设计与实现 作者:霍春阳(HcySunYang) ISBN:978-7-115-58386-4 本书由北京图灵文化发展有限公司发行数字版。版权所有,侵权必 究。 您购买的图灵电子书仅供您个人使用,未经授权,不得以任何方式复 制和传播本书内容。 我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产 权。 如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该 帐号等维权措施,并可能追究法律责任。
Page
3
序 前言 读者对象 本书内容 本书结构 源代码及勘误 致谢 第一篇 框架设计概览 第 1 章 权衡的艺术 1.1 命令式和声明式 1.2 性能与可维护性的权衡 1.3 虚拟 DOM 的性能到底如何 1.4 运行时和编译时 1.5 总结 第 2 章 框架设计的核心要素 2.1 提升用户的开发体验 2.2 控制框架代码的体积 2.3 框架要做到良好的 Tree-Shaking 2.4 框架应该输出怎样的构建产物 2.5 特性开关 2.6 错误处理 2.7 良好的 TypeScript 类型支持 2.8 总结 第 3 章 Vue.js 3 的设计思路 3.1 声明式地描述 UI 3.2 初识渲染器 3.3 组件的本质 3.4 模板的工作原理 3.5 Vue.js 是各个模块组成的有机整体
Page
4
3.6 总结 第二篇 响应系统 第 4 章 响应系统的作用与实现 4.1 响应式数据与副作用函数 4.2 响应式数据的基本实现 4.3 设计一个完善的响应系统 4.4 分支切换与 cleanup 4.5 嵌套的 effect 与 effect 栈 4.6 避免无限递归循环 4.7 调度执行 4.8 计算属性 computed 与 lazy 4.9 watch 的实现原理 4.10 立即执行的 watch 与回调执行时机 4.11 过期的副作用 4.12 总结 第 5 章 非原始值的响应式方案 5.1 理解 Proxy 和 Reflect 5.2 JavaScript 对象及 Proxy 的工作原理 5.3 如何代理 Object 5.4 合理地触发响应 5.5 浅响应与深响应 5.6 只读和浅只读 5.7 代理数组 5.7.1 数组的索引与 length 5.7.2 遍历数组 5.7.3 数组的查找方法 5.7.4 隐式修改数组长度的原型方法 5.8 代理 Set 和 Map
Page
5
5.8.1 如何代理 Set 和 Map 5.8.2 建立响应联系 5.8.3 避免污染原始数据 5.8.4 处理 forEach 5.8.5 迭代器方法 5.8.6 values 与 keys 方法 5.9 总结 第 6 章 原始值的响应式方案 6.1 引入 ref 的概念 6.2 响应丢失问题 6.3 自动脱 ref 6.4 总结 第三篇 渲染器 第 7 章 渲染器的设计 7.1 渲染器与响应系统的结合 7.2 渲染器的基本概念 7.3 自定义渲染器 7.4 总结 第 8 章 挂载与更新 8.1 挂载子节点和元素的属性 8.2 HTML Attributes 与 DOM Properties 8.3 正确地设置元素属性 8.4 class 的处理 8.5 卸载操作 8.6 区分 vnode 的类型 8.7 事件的处理 8.8 事件冒泡与更新时机问题 8.9 更新子节点
Page
6
8.10 文本节点和注释节点 8.11 Fragment 8.12 总结 第 9 章 简单 Diff 算法 9.1 减少 DOM 操作的性能开销 9.2 DOM 复用与 key 的作用 9.3 找到需要移动的元素 9.4 如何移动元素 9.5 添加新元素 9.6 移除不存在的元素 9.7 总结 第 10 章 双端 Diff 算法 10.1 双端比较的原理 10.2 双端比较的优势 10.3 非理想状况的处理方式 10.4 添加新元素 10.5 移除不存在的元素 10.6 总结 第 11 章 快速 Diff 算法 11.1 相同的前置元素和后置元素 11.2 判断是否需要进行 DOM 移动操作 11.3 如何移动元素 11.4 总结 第四篇 组件化 第 12 章 组件的实现原理 12.1 渲染组件 12.2 组件状态与自更新 12.3 组件实例与组件的生命周期
Page
7
12.4 props 与组件的被动更新 12.5 setup 函数的作用与实现 12.6 组件事件与 emit 的实现 12.7 插槽的工作原理与实现 12.8 注册生命周期 12.9 总结 第 13 章 异步组件与函数式组件 13.1 异步组件要解决的问题 13.2 异步组件的实现原理 13.2.1 封装 defineAsyncComponent 函数 13.2.2 超时与 Error 组件 13.2.3 延迟与 Loading 组件 13.2.4 重试机制 13.3 函数式组件 13.4 总结 第 14 章 内建组件和模块 14.1 KeepAlive 组件的实现原理 14.1.1 组件的激活与失活 14.1.2 include 和 exclude 14.1.3 缓存管理 14.2 Teleport 组件的实现原理 14.2.1 Teleport 组件要解决的问题 14.2.2 实现 Teleport 组件 14.3 Transition 组件的实现原理 14.3.1 原生 DOM 的过渡 14.3.2 实现 Transition 组件 14.4 总结 第五篇 编译器
Page
8
第 15 章 编译器核心技术概览 15.1 模板 DSL 的编译器 15.2 parser 的实现原理与状态机 15.3 构造 AST 15.4 AST 的转换与插件化架构 15.4.1 节点的访问 15.4.2 转换上下文与节点操作 15.4.3 进入与退出 15.5 将模板 AST 转为 JavaScript AST 15.6 代码生成 15.7 总结 第 16 章 解析器 16.1 文本模式及其对解析器的影响 16.2 递归下降算法构造模板 AST 16.3 状态机的开启与停止 16.4 解析标签节点 16.5 解析属性 16.6 解析文本与解码 HTML 实体 16.6.1 解析文本 16.6.2 解码命名字符引用 16.6.3 解码数字字符引用 16.7 解析插值与注释 16.8 总结 第 17 章 编译优化 17.1 动态节点收集与补丁标志 17.1.1 传统 Diff 算法的问题 17.1.2 Block 与 PatchFlags 17.1.3 收集动态节点
Page
9
17.1.4 渲染器的运行时支持 17.2 Block 树 17.2.1 带有 v-if 指令的节点 17.2.2 带有 v-for 指令的节点 17.2.3 Fragment 的稳定性 17.3 静态提升 17.4 预字符串化 17.5 缓存内联事件处理函数 17.6 v-once 17.7 总结 第六篇 服务端渲染 第 18 章 同构渲染 18.1 CSR、SSR 以及同构渲染 18.2 将虚拟 DOM 渲染为 HTML 字符串 18.3 将组件渲染为 HTML 字符串 18.4 客户端激活的原理 18.5 编写同构的代码 18.5.1 组件的生命周期 18.5.2 使用跨平台的 API 18.5.3 只在某一端引入模块 18.5.4 避免交叉请求引起的状态污染 18.5.5 <ClientOnly> 组件 18.6 总结 作者简介
Page
10
序 在这本书问世之前,我就已经看过霍春阳的Vue.js 3源码解读,当 时就很欣赏他对技术细节的专注和投入。后来春阳为Vue.js 3提交了大 量补丁,修复了一些非常深层的渲染更新bug,为Vue.js 3做出了很多贡 献,成为了官方团队成员。春阳对Vue.js 3源码的理解来自参与源码的 维护中,这是深入理解开源项目最有难度但也最有效的途径。也因 此,这本书对Vue.js 3技术细节的分析非常可靠,对于需要深入理解 Vue.js 3的用户会有很大的帮助。 春阳对Vue.js的高层设计思想的理解也非常精准,并且在框架的设 计权衡层面有自己的深入思考。这可能是这本书最不同于市面上其他 纯粹的“源码分析”类图书的地方:它从高层的设计角度探讨框架需要 关注的问题,从而帮助读者更好地理解一些具体的实现为何要做出这 样的选择。 前端是一个变化很快的领域,新的技术不断出现,Vue.js本身也在 不断地进化,我们还会继续探索更优化的实现细节。但即使抛开具体 的实现,这本书也可以作为现代前端框架设计的一个非常有价值的参 考。 尤雨溪,Vue.js作者
Page
11
前言 Vue.js 作为最流行的前端框架之一,在 2020 年 9 月 18 日,正式迎 来了它的 3.0 版本。得益于 Vue.js 2 的设计经验,Vue.js 3.0 不仅带来了 诸多新特性,还在框架设计与实现上做了很多创新。在一定程度上, 我们可以认为 Vue.js 3.0“还清”了在 Vue.js 2 中欠下的技术债务。 在我看来,Vue.js 3.0 是一个非常成功的项目。它秉承了 Vue.js 2 的易用性。同时,相比 Vue.js 2,Vue.js 3.0 甚至做到了使用更少的代码 来实现更多的功能。 Vue.js 3.0 在模块的拆分和设计上做得非常合理。模块之间的耦合 度非常低,很多模块可以独立安装使用,而不需要依赖完整的 Vue.js 运行时,例如 @vue/reactivity 模块。 Vue.js 3.0 在设计内建组件和模块时也花费了很多精力,配合构建 工具以及 Tree-Shaking 机制,实现了内建能力的按需引入,从而实现 了用户 bundle 的体积最小化。 Vue.js 3.0 的扩展能力非常强,我们可以编写自定义的渲染器,甚 至可以编写编译器插件来自定义模板语法。同时,Vue.js 3.0 在用户体 验上也下足了功夫。 Vue.js 3.0 的优点包括但不限于上述这些内容。既然 Vue.js 3.0 的优 点如此之多,那么框架设计者是如何设计并实现这一切的呢?实际 上,理解 Vue.js 3.0 的核心设计思想非常重要。它不仅能够让我们更加 从容地面对复杂问题,还能够指导我们在其他领域进行架构设计。 另外,Vue.js 3.0 中很多功能的设计需要谨遵规范。例如,想要使 用 Proxy 实现完善的响应系统,就必须从 ECMAScript 规范入手,而 Vue.js 的模板解析器则遵从 WHATWG 的相关规范。所以,在理解 Vue.js 3.0 核心设计思想的同时,我们还能够间接掌握阅读和理解规 范,并据此编写代码的方法。 读者对象
Page
12
本书的目标读者包括: 对 Vue.js 2/3 具有上手经验,且希望进一步理解 Vue.js 框架设计原 理的开发人员; 没有使用过 Vue.js,但对 Vue.js 框架设计感兴趣的前端开发人员。 本书内容 本书内容并非“源码解读”,而是建立在笔者对 Vue.js 框架设计的 理解之上,以由简入繁的方式介绍如何实现 Vue.js 中的各个功能模 块。 本书将尽可能地从规范出发,实现功能完善且严谨的 Vue.js 功能 模块。例如,通过阅读 ECMAScript 规范,基于 Proxy 实现一个完善 的响应系统;通过阅读 WHATWG 规范,实现一个类 HTML 语法的模 板解析器,并在此基础上实现一个支持插件架构的模板编译器。 除此之外,本书还会讨论以下内容: 框架设计的核心要素以及框架设计过程中要做出的权衡; 三种常见的虚拟 DOM(Virtual DOM)的 Diff 算法; 组件化的实现与 Vue.js 内建组件的原理; 服务端渲染、客户端渲染、同构渲染之间的差异,以及同构渲染 的原理。 本书结构 本书分为 6 篇,共 18 章,各章的简介如下。 第一篇(框架设计概览):共 3 章。 第 1 章主要讨论了命令式和声明式这两种范式的差异,以及 二者对框架设计的影响,还讨论了虚拟 DOM 的性能状况,最 后介绍了运行时和编译时的相关知识,并介绍了 Vue.js 3.0 是 一个运行时 + 编译时的框架。 第 2 章主要从用户的开发体验、控制框架代码的体积、Tree- Shaking 的工作机制、框架产物、特性开关、错误处理、
Page
13
TypeScript 支持等几个方面出发,讨论了框架设计者在设计框 架时应该考虑的内容。 第 3 章从全局视角介绍 Vue.js 3.0 的设计思路,以及各个模块 之间是如何协作的。 第二篇(响应系统):共 3 章。 第 4 章从宏观视角讲述了 Vue.js 3.0 中响应系统的实现机制。 从副作用函数开始,逐步实现一个完善的响应系统,还讲述 了计算属性和 watch 的实现原理,同时讨论了在实现响应系 统的过程中所遇到的问题,以及相应的解决方案。 第 5 章从 ECMAScript 规范入手,从最基本的 Proxy、 Reflect 以及 JavaScript 对象的工作原理开始,逐步讨论了 使用 Proxy 代理 JavaScript 对象的方式。 第 6 章主要讨论了 ref 的概念,并基于 ref 实现原始值的响 应式方案,还讨论了如何使用 ref 解决响应丢失问题。 第三篇(渲染器):共 5 章。 第 7 章主要讨论了渲染器与响应系统的关系,讲述了两者如 何配合工作完成页面更新,还讨论了渲染器中的一些基本名 词和概念,以及自定义渲染器的实现与应用。 第 8 章主要讨论了渲染器挂载与更新的实现原理,其中包括 子节点的处理、属性的处理和事件的处理。当挂载或更新组 件类型的虚拟节点时,还要考虑组件生命周期函数的处理 等。 第 9 章主要讨论了“简单 Diff 算法”的工作原理。 第 10 章主要讨论了“双端 Diff 算法”的工作原理。 第 11 章主要讨论了“快速 Diff 算法”的工作原理。 第四篇(组件化):共 3 章。 第 12 章主要讨论了组件的实现原理,介绍了组件自身状态的 初始化,以及由自身状态变化引起的组件自更新,还介绍了 组件的外部状态(props)、由外部状态变化引起的被动更 新,以及组件事件和插槽的实现原理。 第 13 章主要介绍了异步组件和函数式组件的工作机制和实现 原理。对于异步组件,我们还讨论了超时与错误处理、延迟 展示 Loading 组件、加载重试等内容。 第 14 章主要介绍了 Vue.js 内建的三个组件的实现原理,即 KeepAlive、Teleport和Transition 组件。 第五篇(编译器):共 3 章。
Page
14
第 15 章首先讨论了 Vue.js 模板编译器的工作流程,接着讨论 了 parser 的实现原理与状态机,以及 AST 的转换与插件化 架构,最后讨论了生成渲染函数代码的具体实现。 第 16 章主要讨论了如何实现一个符合 WHATWG 组织的 HTML 解析规范的解析器,内容涵盖解析器的文本模式、文 本模式对解析器的影响,以及如何使用递归下降算法构造模 板 AST。在解析文本内容时,我们还讨论了如何根据规范解 码字符引用。 第 17 章主要讨论了 Vue.js 3.0 中模板编译优化的相关内容。 具体包括:Block 树的更新机制、动态节点的收集、静态提 升、预字符串化、缓存内联事件处理函数、v-once 等优化机 制。 第六篇(服务端渲染):1 章。 第 18 章主要讨论了 Vue.js 同构渲染的原理。首先探讨了 CSR、SSR 以及同构渲染等方案各自的优缺点,然后探讨了 Vue.js 进行服务端渲染和客户端激活的原理,最后总结了编写 同构代码时的注意事项。 源代码及勘误 在学习本书时,书中所有代码均可通过手敲进行试验和学习,你 也可以从GitHub(HcySunYang)下载所有源代码 。我将尽最大努力确 保正文和源代码无误。但金无足赤,书中难免存在一些错误。如果读 者发现任何错误,包括但不限于别字、代码片段、描述有误等,请及 时反馈给我。本书勘误请至GitHub(HcySunYang)查看或提交 。 或访问图灵社区本书主页下载。——编者注 也可访问图灵社区本书主页查看或提交勘误。——编者注 致谢 这本书的诞生,要感谢很多与之有直接或间接关系的人和物。下 面的致谢不分先后,仅按照我特定的逻辑顺序组织编写。 1 2 1 2
Page
15
首先要感谢 Vue.js 这个框架。毫无疑问,Vue.js 为世界创造了价 值,无数的企业和个人开发者从中受益。当然,更要感谢 Vue.js 的作 者尤雨溪以及Vue.js 团队的其他所有成员,良好的团队运作使得 Vue.js 能够持续发展。没有 Vue.js 就不可能有今天这本书。 除此之外,我还要感谢裕波老师的引荐和王军花老师的信任,使 得我有机会来完成这样一本自己比较擅长的书。在写书的过程中,王 军花老师全程热心细致的工作让我对完成编写任务的信心得到了极大 的提升。再次向裕波老师和王军花老师表示由衷的感谢,非常感谢。 还要感谢曾经共事过的一位朋友,张啸。他为这本书提出了很多 宝贵意见,同时还细心地帮忙检查错别字和语句的表达问题。 感谢罗勇林,这是我另一位很特殊的朋友。可以说,没有他,我 甚至不可能走上程序员的道路,更不可能写出这样一本书。感谢你, 兄弟。 当然了,我还要感谢刚刚和我成为合法夫妻的爱人。在我写书的 时候,她还是我的女朋友,为了顺利地完成这本书和一些其他原因, 我几乎在家全职写作,期间只有少量收入甚至没有收入。她从来没有 抱怨过,还经常鼓励我,我还总开玩笑地对她说:“不然你养我算 了。”当这本书出版的时候,她已经成为我的合法妻子,这本书也是我 送给她的礼物之一,谢谢你。
Page
16
第一篇 框架设计概览 第 1 章 权衡的艺术 第 2 章 框架设计的核心要素 第 3 章 Vue.js 3 的设计思路
Page
17
第 1 章 权衡的艺术 “框架设计里到处都体现了权衡的艺术。” 在深入讨论 Vue.js 3 各个模块的实现思路和细节之前,我认为有必 要先来讨论视图层框架设计方面的内容。为什么呢?这是因为当我们 设计一个框架的时候,框架本身的各个模块之间并不是相互独立的, 而是相互关联、相互制约的。因此作为框架设计者,一定要对框架的 定位和方向拥有全局的把控,这样才能做好后续的模块设计和拆分。 同样,作为学习者,我们在学习框架的时候,也应该从全局的角度对 框架的设计拥有清晰的认知,否则很容易被细节困住,看不清全貌。 另外,从范式的角度来看,我们的框架应该设计成命令式的还是 声明式的呢?这两种范式有何优缺点?我们能否汲取两者的优点?除 此之外,我们的框架要设计成纯运行时的还是纯编译时的,甚至是运 行时+编译时的呢?它们之间又有何差异?优缺点分别是什么?这里面 都体现了“权衡”的艺术。 1.1 命令式和声明式 从范式上来看,视图层框架通常分为命令式和声明式,它们各有 优缺点。作为框架设计者,应该对两种范式都有足够的认知,这样才 能做出正确的选择,甚至想办法汲取两者的优点并将其捏合。 接下来,我们先来看看命令式框架和声明式框架的概念。早年间 流行的 jQuery 就是典型的命令式框架。命令式框架的一大特点就是关 注过程。例如,我们把下面这段话翻译成对应的代码: 01 - 获取 id 为 app 的 div 标签 02 - 它的文本内容为 hello world 03 - 为其绑定点击事件 04 - 当点击时弹出提示:ok 对应的代码为:
Page
18
01 $('#app') // 获取 div 02 .text('hello world') // 设置文本内容 03 .on('click', () => { alert('ok') }) // 绑定点击事件 以上就是 jQuery 的代码示例,考虑到有些读者可能没有用过 jQuery,因此我们再用原生 JavaScript 来实现同样的功能: 01 const div = document.querySelector('#app') // 获取 div 02 div.innerText = 'hello world' // 设置文本内容 03 div.addEventListener('click', () => { alert('ok') }) // 绑定点击事 件 可以看到,自然语言描述能够与代码产生一一对应的关系,代码 本身描述的是“做事的过程”,这符合我们的逻辑直觉。 那么,什么是声明式框架呢?与命令式框架更加关注过程不同, 声明式框架更加关注结果。结合 Vue.js,我们来看看如何实现上面自 然语言描述的功能: 01 <div @click="() => alert('ok')">hello world</div> 这段类 HTML 的模板就是 Vue.js 实现如上功能的方式。可以看 到,我们提供的是一个“结果”,至于如何实现这个“结果”,我们并不关 心,这就像我们在告诉 Vue.js:“嘿,Vue.js,看到没,我要的就是一个 div,文本内容是 hello world,它有个事件绑定,你帮我搞定 吧。”至于实现该“结果”的过程,则是由 Vue.js 帮我们完成的。换句话 说,Vue.js 帮我们封装了过程。因此,我们能够猜到 Vue.js 的内部实 现一定是命令式的,而暴露给用户的却更加声明式。 1.2 性能与可维护性的权衡 命令式和声明式各有优缺点,在框架设计方面,则体现在性能与 可维护性之间的权衡。这里我们先抛出一个结论:声明式代码的性能 不优于命令式代码的性能。
Page
19
还是拿上面的例子来说,假设现在我们要将 div 标签的文本内容 修改为 hello vue3,那么如何用命令式代码实现呢?很简单,因为 我们明确知道要修改的是什么,所以直接调用相关命令操作即可: 01 div.textContent = 'hello vue3' // 直接修改 现在思考一下,还有没有其他办法比上面这句代码的性能更好? 答案是“没有”。可以看到,理论上命令式代码可以做到极致的性能优 化,因为我们明确知道哪些发生了变更,只做必要的修改就行了。但 是声明式代码不一定能做到这一点,因为它描述的是结果: 01 <!-- 之前: --> 02 <div @click="() => alert('ok')">hello world</div> 03 <!-- 之后: --> 04 <div @click="() => alert('ok')">hello vue3</div> 对于框架来说,为了实现最优的更新性能,它需要找到前后的差 异并只更新变化的地方,但是最终完成这次更新的代码仍然是: 01 div.textContent = 'hello vue3' // 直接修改 如果我们把直接修改的性能消耗定义为 A,把找出差异的性能消 耗定义为 B,那么有: 命令式代码的更新性能消耗 = A 声明式代码的更新性能消耗 = B + A 可以看到,声明式代码会比命令式代码多出找出差异的性能消 耗,因此最理想的情况是,当找出差异的性能消耗为 0 时,声明式代 码与命令式代码的性能相同,但是无法做到超越,毕竟框架本身就是 封装了命令式代码才实现了面向用户的声明式。这符合前文中给出 的性能结论:声明式代码的性能不优于命令式代码的性能。 既然在性能层面命令式代码是更好的选择,那么为什么 Vue.js 要 选择声明式的设计方案呢?原因就在于声明式代码的可维护性更强。 从上面例子的代码中我们也可以感受到,在采用命令式代码开发的时
Page
20
候,我们需要维护实现目标的整个过程,包括要手动完成 DOM 元素 的创建、更新、删除等工作。而声明式代码展示的就是我们要的结 果,看上去更加直观,至于做事儿的过程,并不需要我们关心,Vue.js 都为我们封装好了。 这就体现了我们在框架设计上要做出的关于可维护性与性能之间 的权衡。在采用声明式提升可维护性的同时,性能就会有一定的损 失,而框架设计者要做的就是:在保持可维护性的同时让性能损失最 小化。 1.3 虚拟 DOM 的性能到底如何 考虑到有些读者可能不知道什么是虚拟 DOM,这里我们不会对其 做深入讨论,但这既不影响你理解本节内容,也不影响你阅读后续章 节。如果实在看不明白,也没关系,至少有个印象,等后面我们深入 讲解虚拟 DOM 后再回来看这里的内容,相信你会有不同的感受。 前文说到,声明式代码的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗,因此,如果我们能够最小化找出差异的性能 消耗,就可以让声明式代码的性能无限接近命令式代码的性能。而所 谓的虚拟 DOM,就是为了最小化找出差异这一步的性能消耗而出现 的。 至此,相信你也应该清楚一件事了,那就是采用虚拟 DOM 的更新 技术的性能理论上不可能比原生 JavaScript 操作 DOM 更高。这里我们 强调了理论上三个字,因为这很关键,为什么呢?因为在大部分情况 下,我们很难写出绝对优化的命令式代码,尤其是当应用程序的规模 很大的时候,即使你写出了极致优化的代码,也一定耗费了巨大的精 力,这时的投入产出比其实并不高。 那么,有没有什么办法能够让我们不用付出太多的努力(写声明 式代码),还能够保证应用程序的性能下限,让应用程序的性能不至 于太差,甚至想办法逼近命令式代码的性能呢?这其实就是虚拟 DOM 要解决的问题。 不过前文中所说的原生 JavaScript 实际上指的是像 document.createElement 之类的 DOM 操作方法,并不包含
Comments 0
Loading comments...
Reply to Comment
Edit Comment