第一章 权衡艺术

命令式和声明式

从范式上看,视图层框架分为命令式和声明式。

命令式:

一大特点是:关注过程

声明式:

一大特点是:关注结果

性能与可维护性

声明式代码的性能不优于命令式代码的性能

框架本身就是封装了命令式代码才实现了面向用户的声明式

声明式代码的可维护性强

虚拟DOM的性能

为了使声明式的性能更接近命令式的性能,这就是虚拟DOM的作用

通过innerHTML创建页面的性能:HTML字符串拼接的计算量+innerHTML的DOM计算量

虚拟DOM创建页面的性能:创建JavaScript对象的计算量+创建真实DOM的计算量

innerHTML更新页面的时候:要重新构建HTML字符串,再重新设置DOM元素的innerHTML属性。其实就是要销毁所有旧的DOM元素,再全量的创建新的DOM元素。

虚拟DOM更新页面的时候:比较新旧虚拟DOM,找到变化的元素更新它

性能:原生JavaScript > 虚拟DOM > innerHTML(模板)

运行时和编译时

纯运行时:

编写一个Render函数

提供一个树型结构的数据对象:

1
2
3
4
5
6
01 const obj = {
02 tag: 'div',
03 children: [
04 { tag: 'span', children: 'hello world' }
05 ]
06 }

Render函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
01 function Render(obj, root) {
02 const el = document.createElement(obj.tag)
03 if (typeof obj.children === 'string') {
04 const text = document.createTextNode(obj.children)
05 el.appendChild(text)
06 } else if (obj.children) {
07 // 数组,递归调用 Render,使用 el 作为 root 参数
08 obj.children.forEach((child) => Render(child, el))
09 }
10
11 // 将元素添加到 root
12 root.appendChild(el)
13 }

使用:

1
2
3
4
5
6
7
8
01 const obj = {
02 tag: 'div',
03 children: [
04 { tag: 'span', children: 'hello world' }
05 ]
06 }
07 // 渲染到 body 下
08 Render(obj, document.body)

运行时+编译时

编写Compiler的程序,作用是把HTML字符串编译成树型结构的数据对象

使用:

1
2
3
4
5
6
7
8
9
01 const html = `
02 <div>
03 <span>hello world</span>
04 </div>
05 `
06 // 调用 Compiler 编译得到树型结构的数据对象
07 const obj = Compiler(html)
08 // 再调用 Render 进行渲染
09 Render(obj, document.body)

纯编译时:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBZ0pbQQ-1686448242740)(C:\Users\virtue\AppData\Roaming\Typora\typora-user-images\image-20230213173530302.png)]

这个时候只需要Compiler函数就可以了,只通过编译器编译就可以了。

第二章 框架设计的核心要素

一. 提升用户的开发体验

二. 控制框架代码的体积

三. 框架要做到良好的Tree-Shaking

Tree-Shaking 指的是消除哪些永远不会被执行的代码,排除dead code

实现Tree-Shaking必须满足模板是ESM(ES Module)依赖ESM的静态结构

Tree-Shaking工作原理:

目录结构
1
2
3
4
01 ├── demo
02 │ └── package.json
03 │ └── input.js
04 │ └── utils.js

首先安装rollup.js

1
2
01 yarn add rollup -D
02 # 或者 npm install rollup -D

input.jsutil.js文件的内容

1
2
3
4
5
6
7
8
9
10
01 // input.js
02 import { foo } from './utils.js'
03 foo()
04 // utils.js
05 export function foo(obj) {
06 obj && obj.foo
07 }
08 export function bar(obj) {
09 obj && obj.bar
10 }

input.js文件为入口,输出ESM,输出文件的名字叫作bundle.js

1
01 npx rollup input.js -f esm -o bundle.js

bundle.js的内容

1
2
3
4
5
01 // bundle.js
02 function foo(obj) {
03 obj && obj.foo
04 }
05 foo();

Tree-Shaking中的第二个关键点——副作用

如果一个函数产生了副作用,那么就不会被消除

副作用:当调用函数的时候会对外界产生影响

1
2
3
4
01 //input.js
02 import {foo} from './utils'
03
04 /*#__PURE__*/ foo()

注释代码 /#PURE/,其作用就是告诉 rollup.js,对于foo函数的调用不会产生副作用

IIFE格式的资源:iife 立刻调用的函数表达式

ESM格式的资源:esm

vue.esm-browser.js中的-browser字样的ESM资源是直接给

cjs格式的资源:cjs 全称:CommonJS

文章作者: Mr. Fortunate
文章链接: https://www.fortunate.cool/2023/06/11/%E6%8E%A8%E8%8D%90/Vue.js%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 fortunate

评论