简介一下集体浏览 vue 源码的姿态,有倡议欢送评论区补充哈~
一、源码浏览姿态
1. 先整体 – 后细节
- 先弄清楚源码分为哪几个模块,整套流程是怎么将各个模块串起来的。
- 而后细化理解每个模块的外围原理。
2. 站在他人的肩膀上
- 不必一股脑扎进源码仓库里一点点啃,这样很低效,实用于对源码较为理解的人
- 举荐先读他人的源码简介,源码剖析,弄清楚脉络,还有每个局部的大略性能和外围流程。心里带着思路去看源码实现。
- 少数状况不须要逐行代码的细究,但针对某些外围性能的实现须要细究,例如:虚构 dom、diff 算法、数据驱动、响应式实现以及组件化等外围的性能的外围实现举荐细看。
3. 读多遍
- 一次粗读 :看整体流程,看每个模块的外围性能和职责,领会平时写的代码在源码外面通过了什么步骤体现到了页面上。
- 二次精读 :看细节实现,弄清楚外围模块的实现形式(如弄懂 diff 算法思路,最好本人入手实现)。
- 三次领悟 :领悟源码整体架构和设计思维,领会每个模块之间如何配合合作,架构如何组织。
二、步骤
- 依赖剖析组装:路由、父子组件层级
- 模版编译:解析成 AST 语法树,进而构建虚构 dom 树
- 装载页面:虚构 dom 整体转化为实在 dom
- 部分更新:响应式数据监控到变动,diff 比拟数据变动前后的虚构 dom 树差别,部分更新 dom
- 销毁:销毁虚构 dom,移除 dom
三、vue 源码导读
- template 格调、对象配置格调
- 虚构 dom 思维(js 对象操作代替 dom 操作)
- diff 算法思维(同层比拟,增加、挪动、删除)
- 组件化思维(组件编译、组件通信)
- 数据响应式(依赖收集、派发更新,公布订阅)
四、vue3 新个性理解
vue2.x 的痛点:
- 源码本身的维护性;
- 数据量大后带来的渲染和更新的性能问题;
- 一些想舍弃但为了兼容始终保留的鸡肋 API 等;
- TypeScript 反对;
vue3.0 优化点:
- 一、应用 monorepo 治理源码
- 二、应用 TypeScript 开发源码
- 三、性能优化 1. 源码体积优化 2. 数据劫持优化 Proxy 3. 编译优化 4.diff 算法优化
- 四、语法 API 优化:Composition API
插一个题外话,小编整顿了下用 Vue 3.0 来写个小程序框架的 PDF 材料,感兴趣的小伙伴们请点击这里支付
五、细究一下 diff 算法
vue2 的 diff
组件更新外围是响应式数据监控到数据的扭转,从新生成了虚构 dom 树,而后通过 diff 算法计算出前后虚构 dom 树的差别点,更新 dom 时只更新变动的局部。快问快答:
1. 为什么要 diff?
答:O(n^3) 意味着如果要展现 1000 个节点,就要顺次执行上十亿次的比拟,无奈接受大数据量的比照。
间接比拟和批改两个树的复杂度为什么是 n^3?
答:老树的每一个节点都去遍历新树的节点,直到找到新树对应的节点。那么这个流程就是 O(n^2),再紧接着找到不同之后,再计算最短批改间隔而后批改节点,这里是 O(n^3)。
2. diff 的策略是什么?有什么依据?
答:1、Web UI 中 DOM 节点跨层级的挪动操作特地少,能够忽略不计,因而仅进行同层比拟。2、如果父节点不同,放弃对子节点的比拟,间接删除旧节点而后增加新的节点从新渲染;3、如果子节点有变动,Virtual DOM 不会计算变动的是什么,而是从新渲染。4、同级多个节点可通过惟一的 key 比照异同;
3. diff 流程是什么?
答:新旧节点不同:创立新节点 ➜ 更新父占位符节点 ➜ 删除旧节点;新旧节点雷同且没有子节点:不变;新旧节点雷同且都有子节点:遍历子节点同级比拟,做挪动、增加、删除三个操作,具体见下图;
vue3.0 的 diff
深度递归遍历 vnode 树,节点的标签和 key 雷同认为是同一个节点则更新,不同则删除,而后解决子节点。子节点分这几种状况解决:纯文本、vnode 数组和空
空往往意味着增加或删除;纯文本雷同间接更新 innerText,不同则删除;新旧子节点都是 vnode 数组则 diff 算法来解决;
vue3.0 diff 算法思维
- 编译模版时进行动态剖析,标记动静节点,diff 比照差别时仅比照动静节点(性能晋升显著);
- diff 算法先去头去尾,借此缩短遍历比照数组长度(对数组插入和删除操作性能优化显著);
- 通过对更新前后子节点数组建设映射表的形式,将 O(n^2) 复杂度的遍历升高到 O(n);
- 通过最长递增子序列办法了来 diff 前后的子节点数组,缩小挪动操作的次数;
最长递增子序列算法实现 :
/*
* 寻找最长递增子序列
* 应用动静布局思维,a -> c = a -> b + b -> c
* 其中 p 数组存储的是从 p[p[i]] 到 p[i] 的最长递增子序列索引,也就是前一个 b 的索引;* r 数组存储最初一个元素也就是 c 的索引
*/
function getSequenceOfLIS(arr) {const p = [0];
const result = [0];
for (let i = 0; i < arr.length; i ++) {const val = arr[i];
const top = result[result.length - 1];
if (arr[top] < val) {p[i] = top;
result.push(i);
continue;
}
// 二分法搜寻
let l = 0, r = result.length - 1;
while(l < r) {const c = (l + r) >> 1;
if (arr[result] < val) {l = c + 1;} else {r = c;}
}
if (val < arr[result[l]]) {if (l > 0) {p[i] = result[l - 1]
}
result[l] = i;
}
}
// 回朔 p 数组,找出最长递增子序列
let preIndex = result[result.length - 1];
for (let i = result.length - 1; i > 0; i --) {result[i] = preIndex;
preIndex = p[preIndex]
}
return result;
}
浏览 vue 源码姿态小伙伴们你们学废了嘛,你们都是如何浏览的呢,欢送评论留言通知小编哦。
还有想学用 Vue 3.0 来写个小程序框架的小伙伴们记得支付!点击这里也是一样能够支付的
求点赞求反对!提前祝小伙伴们五一高兴嗷!