---
title: Vue.js 设计与实现 - 1 | 权衡的艺术 date: 2022-07-02 tags:
- 书籍阅读 categories:
- vue
总结
- 视图层框架:命令式、声明式
- 声明式的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗
- 对比了原生js操作DOM、虚拟DOM和innerHTML三者的性能,这三者性能无法简单下结论。需要结合页面大小、变更部分大小、行为是创建页面还是更新页面去判断。从结果而言虚拟DOM性能还不错
- 运行时 + 编译时,保证了不错的灵活度,性能也不赖。
1. 命令式和声明式
视图层框架:
- 命令式:jQeury,关注过程。
自然语言可以和代码一一对应。js$(#app) // 获取div .text('hello') // 设置文本内容 .on('click', () => {alert('ok')}) // 绑定点击事件
- 声明式:Vue,关注结果。
vue为我们提供了结果,封装了过程,其内部的实现是命令式,而暴露给用户的是声明式。
封装了命令式代码才实现了面向用户的声明式.html<div @click="() => alert('ok')">hello</div>
2. 性能和可维护性的权衡
结论:声明式代码的性能 不优于 命令式代码的性能
优缺点:
- 命令式:性能好,维护性差。实际开发中难以写出性能最优的命令式代码(费精力)。
- 声明式:性能差,维护性好。
性能消耗计算:
- 命令式:直接修改性能消耗
- 声明式:找出差异的性能消耗 + 直接修改的性能消耗
框架设计目的:保持可维护性的同时,让性能损失最小化。所以使用声明式,且尽可能减少【找出差异的性能消耗】。
找出差异的性能消耗可以使用虚拟DOM,只要虚拟DOM的性能足够优秀,那声明式的性能就能无限接近接近命令式的性能。
3. 虚拟DOM
结论:js的性能消耗远 小于 DOM操作的性能消耗
想要性能好,可以在js上找出差异,尽可能减少DOM操作的性能消耗:虚拟DOM
且尽可能优化虚拟DOM,尽量减少【找出差异的性能消耗】。
声明式视图框架Vue,便是使用虚拟DOM
虚拟DOM 和 innerHTML 的区别
innerHTML创建页面的性能:HTML字符串拼接的计算量(在js中拼接) + 销毁/创建所有真实DOM的计算量
特点:全量更新. 只要HTML文本有一点更改,范围内的所有DOM元素就得销毁重新生成虚拟DOM的性能:( 创建JS对象的计算量 + Diff算法计算量 ) + 更新真实DOM的计算量
特点:找到需要修改的元素,仅仅更新该元素.
更新页面时,性能比较:
innerHTML < 虚拟DOM < 原生js Dom操作
性能差 性能不错 性能强
心智负担中 心智负端小 心智负担重
可维护性强 可维护性差
4 运行时、编译时
框架设计
- 纯运行时
- 运行时 + 编译时
- 纯编译时
4.1 纯运行时
const obj = {
tag: 'div',
children: [
{tag: 'span', children: 'hello word'}
]
}
function Render(obj, root) {
const el = document.createElement(obj.tag)
if(typeof obj.children === 'string') {
const text = document.createTextNode(obj.children)
el.appendChild(text)
} else if(obj.children) {
obj.children.forEach(child => Render(child, el))
}
root.appendChild(el)
}
Render(obj, document.body)
上面的代码在运行时,通过调用Render
函数,传递一个树的数据结构
,便可以创建对应的HTML添加到文档中,这便是 纯运行时 框架。
如果觉得这个树的数据结构不够直观,想用类似HTML标签的方式描述树的数据结构,需要引入编译器。
编译器Compiler
可以将HTML描述编译成树的数据结构,这样便可以继续调用Render函数
const html = `
<div>
<span>hello word</span>
</div>
`
const obj = Compiler(html) // 编译器编译,获取属性数据结构
Render(obj, document.body)
当然,这里还是纯运行时,或者叫运行时编译。由于多调用了Compiler,对比直接调用Render,会消耗更多性能。
4.2 运行时 + 编译时
我们可以通过构建工具,在构建时便执行Compiler程序将用户提供的内容编译好,等到运行时就无需编译了,对性能非常好。
这便是运行时 + 编译时。
4.3 纯编译时
既然Compiler编译器可以将HTML描述文本编译成树的数据结构,同样它也可以将HTML描述文本直接转成命令行代码。
直接转成命令行代码,跳过了Render函数,性能可能会更好。
4.4 优缺点
纯运行时:
- 灵活度最高,都在运行时执行代码,没有编译过程定下来固定的东西。
- 没有编译过程,没法提前分析用户提供的内容,性能没有其它两个优越
运行时 + 编译时:Vue3
- 有编译过程,可以提前分析用户提供内容,分析出哪些未来会改变,哪些不会从而提前编译好提高运行时的性能。
- 具有不错的灵活度。
纯编译时:Svelte
- 由于不需要任何运行时,直接编译成可执行的命令式代码,性能可能是最好的。
- 但有损灵活度,且内容必须编译后才能使用。
- 跟命令式代码一样,难以写出最理想化的命令式代码,框架真实性能可能达不到理想高度。
疑问
- 感觉有点零散,知识点连不到一起
- 为什么说纯编译时有损灵活度,且内容必须编译后才能使用。我们现在用的框架Vue React等不都有webpack脚手架等去编译吗。这算缺点的化 为什么在运行时+编译时不提这个缺点。
- 纯编译为什么灵活度差?