Vue2响应式系统之嵌套怎么实现
这篇"Vue2响应式系统之嵌套怎么实现"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Vue2响应式系统之嵌套怎么实现"文章吧。
1、场景
在 开发中肯定存在组件嵌套组件的情况,类似于下边的样子。Vue
{{ text }} {{ text }}回到我们之前的响应式系统,模拟一下上边的情况:
import { observe } from "./reactive";import Watcher from "./watcher";const data = { text: "hello, world", inner: "内部",};observe(data);const updateMyComponent = () => { console.log("子组件收到:", data.inner);};const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父组件收到:", data.text);};new Watcher(updateParentComponent);data.text = "hello, liang";可以先 分钟考虑一下上边输出什么?
1
首先回忆一下 会做什么操作。
new Watcher
第一步是保存当前函数,然后执行当前函数前将全局的 赋值为当前 对象。
Dep.target
Watcher
接下来执行 函数的时候,如果读取了相应的属性就会触发 ,从而将当前 收集到该属性的 中。
getter
get
Watcher
Dep
2、执行过程
import { observe } from "./reactive";import Watcher from "./watcher";const data = { text: "hello, world", inner: "内部",};observe(data);const updateMyComponent = () => { console.log("子组件收到:", data.inner);};const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父组件收到:", data.text);};new Watcher(updateParentComponent);data.text = "hello, liang";我们再一步一步理清一下:
new Watcher(updateParentComponent);
将 赋值为保存了 函数的 。
Dep.target
updateParentComponent
Watcher
接下来执行 函数。
updateParentComponent
new Watcher(updateMyComponent);
将 赋值为保存了 函数的 。
Dep.target
updateMyComponent
Watcher
接下来执行 函数。
updateMyComponent
const updateMyComponent = () => { console.log("子组件收到:", data.inner);};// 读取了 inner 变量。// data.inner 的 Dep 收集当前 Watcher(保存了 `updateMyComponent` 函数)const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父组件收到:", data.text);};// 读取了 text 变量。// data.text 的 Dep 收集当前 Watcher (保存了 `updateMyComponent` 函数)
data.text = "hello, liang";
触发 的 函数,执行它依赖的 ,而此时是 函数。
text
set
Watcher
updateMyComponent
所以上边代码最终输出的结果是:
子组件收到: 内部 // new Watcher(updateMyComponent); 时候输出
父组件收到: hello, world // new Watcher(updateParentComponent); 时候输出
子组件收到: 内部 // data.text = "hello, liang"; 输出然而子组件并不依赖 ,依赖 的父组件反而没有执行。
data.text
data.text
3、修复
上边的问题出在我们保存当前正在执行 时候使用的是单个变量 。
Watcher
Dep.target = null; // 静态变量,全局唯一
回忆一下学习 语言或者汇编语言的时候对函数参数的处理:
C
function b(p) { console.log(p);}function a(p) { b("child"); console.log(p);}a("parent");当函数发生嵌套调用的时候,执行 函数的时候我们会先将参数压入栈中,然后执行 函数,同样将参数压入栈中, 函数执行完毕就将参数出栈。此时回到 函数就能正确取到 参数的值了。
a
b
b
a
p
对应于 的收集,我们同样可以使用一个栈来保存,执行函数前将 压入栈,执行函数完毕后将 弹出栈即可。其中, 始终指向栈顶 ,代表当前正在执行的函数。
Watcher
Watcher
Watcher
Dep.target
Watcher
回到 代码中,我们提供一个压栈和出栈的方法。
Dep
import { remove } from "./util";let uid = 0;export default class Dep { ... 省略}Dep.target = null; // 静态变量,全局唯一// The current target watcher being evaluated.// This is globally unique because only one watcher// can be evaluated at a time.const targetStack = [];export function pushTarget(target) { targetStack.push(target); Dep.target = target;}export function popTarget() { targetStack.pop(); Dep.target = targetStack[targetStack.length - 1]; // 赋值为栈顶元素}然后 中,执行函数之前进行入栈,执行后进行出栈。
Watcher
import { pushTarget, popTarget } from "./dep";export default class Watcher { constructor(Fn) { this.getter = Fn; this.depIds = new Set(); // 拥有 has 函数可以判断是否存在某个 id this.deps = []; this.newDeps = []; // 记录新一次的依赖 this.newDepIds = new Set(); this.get(); } /** * Evaluate the getter, and re-collect dependencies. */ get() { /************修改的地方*******************************/ pushTarget(this); // 保存包装了当前正在执行的函数的 Watcher /*******************************************/ let value; try { value = this.getter.call(); } catch (e) { throw e; } finally { /************修改的地方*******************************/ popTarget(); /*******************************************/ this.cleanupDeps(); } return value; } ...}4、测试
回到开头的场景,再来执行一下:
import { observe } from "./reactive";import Watcher from "./watcher";const data = { text: "hello, world", inner: "内部",};observe(data);const updateMyComponent = () => { console.log("子组件收到:", data.inner);};const updateParentComponent = () => { new Watcher(updateMyComponent); console.log("父组件收到:", data.text);};new Watcher(updateParentComponent);data.text = "hello, liang";执行 的时候将 入栈。
new Watcher(updateParentComponent);
Watcher
进入 函数,执行 的时候将 入栈。
updateParentComponent
new Watcher(updateMyComponent);
Watcher
执行 函数, 收集当前 ,执行完毕后 出栈。
updateMyComponent
data.inner
Dep.target
Watcher
继续执行 函数, 收集当前 。
updateParentComponent
data.text
Dep.target
此时依赖就变得正常了, 会触发 函数,从而输出如下:
data.text
updateParentComponent
子组件收到: 内部
父组件收到: hello, world
子组件收到: 内部
父组件收到: hello, liang以上就是关于"Vue2响应式系统之嵌套怎么实现"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。
函数 组件 时候 输出 内容 参数 变量 系统 上边 接下来 全局 正在 代码 地方 场景 属性 情况 文章 知识 篇文章 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 英良网络技术有限公司 计算机网络技术基础心得 滴滴app软件开发价格 中国水稻数据库中心龙粳42 网页数据库如何读取 金刚经下载软件开发 哪些上市公司生产网络安全产品 oa系列软件开发 多台gpu服务器管理软件 数据库结构的指标 未来10年网络安全性 盗版对软件开发的 网络安全 mpa论文 云数据库增加小程序 软件开发辞职做什么 原子性分布式数据库 恒生科技互联网指数 波洞显示服务器异常 数据库字段删除语句怎么写 数据库 视图名称 服务器运维毕业实习报告前言咋写 高考 网络安全 收到网络安全宣传 戴尔超融合服务器 网页设计和软件开发专业哪个好 win8打开服务器管理器 手游服务器怎么重开 明日之后白露山服务器现在叫什么 广州天河招聘软件开发 必须进行查询优化的数据库