Vue2剥丝抽茧-响应式系统完善
这篇文章主要修之前代码存在的一个问题,废话不多说,上代码!
场景
import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: "hello, world",
};
observe(data);
let show = true;
const updateComponent = () => {
if (show) {
console.log(data.text);
show = false;
}
};
new Watcher(updateComponent);
new Watcher(() => console.log("依赖", data.text));
data.text = "123";
先可以 1
分钟思考一下会输出什么。
new Watcher(updateParentComponent);
执行 updateParentComponent
函数,输出 hello, world
,并且 text
的 Dep
收集该 Watcher
。
image-20220403121307975
new Watcher(() => console.log("依赖", data.text));
执行匿名函数,输出 依赖 hello, world
,并且 text
的 Dep
收集该 Watcher
。
image-20220403121807211
data.text = "123";
。
触发 text
的 set
,依次执行 Dep
中的 Watcher
。
先执行 updateParentComponent
。
const updateComponent = () => {
if (show) {
console.log(data.text);
show = false;
}
};
由于之前已经执行过一次了,此时 show
就是 false
了,什么都不会输出。
再执行 () => console.log("依赖", data.text)
,输出 依赖 hello, world
。
是的,上边是我们所期望的样子,但事实上输出结果如下:
image-20220403122245290
出错代码 dep.js:37:26
如下:
image-20220403122317871
调用 update
的时候是,遍历过程中 subs[i]
变成了 undefined
,导致了报错。
需要回忆下 Vue2剥丝抽茧-响应式系统之分支切换 这篇文章里我们做了什么。
image-20220331091857522
如果 Watcher
中的函数不再依赖当前属性,我们就把当前 Watcher
从该属性的 Dep
中移除。
而移除其实就是调用了数组的 splice
方法,直接将 Dep
中的 subs
数组元素进行删除。
removeSub(sub) {
remove(this.subs, sub);
}
export function remove(arr, item) {
if (arr.length) {
const index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
而此时我们正在遍历 subs
数组:
notify() {
for (let i = 0, l = this.subs.length; i < l; i++) {
this.subs[i].update();
}
}
对应上边的例子,原本 subs
数组两个 Watcher
,第一个 Watcher
执行的时候没有访问 data.text
属性,就要把这一个 Watcher
删除了,第二个就移动到第一个的位置了,此时 for
循环中访问第二个位置的 Watcher
因为被移到前边自然就报错了。
修改起来也很容易,我们只需要在循环前,将原有的 subs
数组保存给一个新的数组即可。
notify() {
// stabilize the subscriber list first
const subs = this.subs.slice();
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
}
总
这篇文章比较简单,主要就是循环通知 Watcher
之前把列表另存起来,防止遍历过程中被修改。
相关文章
- Vue3源码05 : Vue3响应式系统源码实现(2/2)
- [ Vue ] vue 设计原理之响应式系统实现笔记( 二 )
- Vue2剥丝抽茧-响应式系统
- Vue2剥丝抽茧-响应式系统之数组
- Vue2剥丝抽茧-响应式系统之set和delete
- Vue2剥丝抽茧-响应式系统之watch
- MySQL数据库:第十五章:MySQL安装到最后一步未响应MySQL Server Instance Configuration Wizard
- 说说Vue响应式系统中的Watcher和Dep的关系-面试进阶
- SpringCloudRPC调用核心原理:RxJava响应式编程框架,聚合操作符
- vue源码分析-响应式系统工作原理_2023-03-01
- 带你深入Vue3响应式系统
- 【教程】Python requests库POST方式接收Stream类型的响应
- (六)监听响应数据的变化
- 响应式系统与React - 笔记
- Bootstrap Studio 4 for Mac(响应式网页设计工具)
- 从Lisp到Vue、React再到 Qwit:响应式编程的发展历程
- SAP ABAP Gateway 系统里 HTTP 请求响应头部字段 DataServiceVersion 的可能取值范围
- ResponsiveAeon:响应式 CSS3 网格系统框架
- Oracle响应文件:一步掌握解决方案(oracle响应文件)
- 利用Redis加速网页响应:优化缓存机制(redis缓存机制)
- 响应式网页设计
- 红色之火零延迟的Redis高可用架构(redis高可用无响应)