成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Vue2剝絲抽繭-響應(yīng)式系統(tǒng)之嵌套

開(kāi)發(fā) 前端
對(duì)應(yīng)于 Watcher 的收集,我們同樣可以使用一個(gè)棧來(lái)保存,執(zhí)行函數(shù)前將 Watcher 壓入棧,執(zhí)行函數(shù)完畢后將 Watcher 彈出棧即可。其中,Dep.target 始終指向棧頂 Watcher ,代表當(dāng)前正在執(zhí)行的函數(shù)。

場(chǎng)景

在 Vue 開(kāi)發(fā)中肯定存在組件嵌套組件的情況,類似于下邊的樣子。

<!-- parent-component -->
<div>
<my-component :text="inner"></my-component>
{{ text }}
<div>

<!-- my-component-->
<div>{{ text }}</div>

回到我們之前的響應(yīng)式系統(tǒng),模擬一下上邊的情況:

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: "hello, world",
inner: "內(nèi)部",
};
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 會(huì)做什么操作。

第一步是保存當(dāng)前函數(shù),然后執(zhí)行當(dāng)前函數(shù)前將全局的 Dep.target 賦值為當(dāng)前 Watcher 對(duì)象。

接下來(lái)執(zhí)行 getter 函數(shù)的時(shí)候,如果讀取了相應(yīng)的屬性就會(huì)觸發(fā) get ,從而將當(dāng)前 Watcher 收集到該屬性的 Dep 中。

執(zhí)行過(guò)程

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: "hello, world",
inner: "內(nèi)部",
};
observe(data);

const updateMyComponent = () => {
console.log("子組件收到:", data.inner);
};

const updateParentComponent = () => {
new Watcher(updateMyComponent);
console.log("父組件收到:", data.text);
};

new Watcher(updateParentComponent);

data.text = "hello, liang";

我們?cè)僖徊揭徊嚼砬逡幌拢?/p>

  • new Watcher(updateParentComponent);

將 Dep.target 賦值為保存了 updateParentComponent 函數(shù)的 Watcher 。

接下來(lái)執(zhí)行 updateParentComponent 函數(shù)。

  • new Watcher(updateMyComponent);

將 Dep.target 賦值為保存了 updateMyComponent 函數(shù)的 Watcher 。

接下來(lái)執(zhí)行 updateMyComponent 函數(shù)。

const updateMyComponent = () => {
console.log("子組件收到:", data.inner);
};

// 讀取了 inner 變量。
// data.inner 的 Dep 收集當(dāng)前 Watcher(保存了 `updateMyComponent` 函數(shù))
const updateParentComponent = () => {
new Watcher(updateMyComponent);
console.log("父組件收到:", data.text);
};
// 讀取了 text 變量。
// data.text 的 Dep 收集當(dāng)前 Watcher (保存了 `updateMyComponent` 函數(shù))
  • data.text = "hello, liang";

觸發(fā) text 的 set 函數(shù),執(zhí)行它依賴的 Watcher ,而此時(shí)是 updateMyComponent 函數(shù)。

所以上邊代碼最終輸出的結(jié)果是:

子組件收到: 內(nèi)部  // new Watcher(updateMyComponent); 時(shí)候輸出
父組件收到:hello, world // new Watcher(updateParentComponent); 時(shí)候輸出
子組件收到: 內(nèi)部 // data.text = "hello, liang"; 輸出

然而子組件并不依賴 data.text,依賴 data.text 的父組件反而沒(méi)有執(zhí)行。

修復(fù)

上邊的問(wèn)題出在我們保存當(dāng)前正在執(zhí)行 Watcher 時(shí)候使用的是單個(gè)變量 Dep.target = null; // 靜態(tài)變量,全局唯一。

回憶一下學(xué)習(xí) C 語(yǔ)言或者匯編語(yǔ)言的時(shí)候?qū)瘮?shù)參數(shù)的處理:

function b(p) {
console.log(p);
}

function a(p) {
b("child");
console.log(p);
}

a("parent");

當(dāng)函數(shù)發(fā)生嵌套調(diào)用的時(shí)候,執(zhí)行 a 函數(shù)的時(shí)候我們會(huì)先將參數(shù)壓入棧中,然后執(zhí)行 b 函數(shù),同樣將參數(shù)壓入棧中,b 函數(shù)執(zhí)行完畢就將參數(shù)出棧。此時(shí)回到 a 函數(shù)就能正確取到 p 參數(shù)的值了。

對(duì)應(yīng)于 Watcher 的收集,我們同樣可以使用一個(gè)棧來(lái)保存,執(zhí)行函數(shù)前將 Watcher 壓入棧,執(zhí)行函數(shù)完畢后將 Watcher 彈出棧即可。其中,Dep.target 始終指向棧頂 Watcher ,代表當(dāng)前正在執(zhí)行的函數(shù)。

回到 Dep 代碼中,我們提供一個(gè)壓棧和出棧的方法。

import { remove } from "./util";

let uid = 0;

export default class Dep {
... 省略
}
Dep.target = null; // 靜態(tài)變量,全局唯一

// 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 中,執(zhí)行函數(shù)之前進(jìn)行入棧,執(zhí)行后進(jìn)行出棧。

import { pushTarget, popTarget } from "./dep";
export default class Watcher {
constructor(Fn) {
this.getter = Fn;
this.depIds = new Set(); // 擁有 has 函數(shù)可以判斷是否存在某個(gè) id
this.deps = [];
this.newDeps = []; // 記錄新一次的依賴
this.newDepIds = new Set();
this.get();
}

/**
* Evaluate the getter, and re-collect dependencies.
*/
get() {
/************修改的地方*******************************/
pushTarget(this); // 保存包裝了當(dāng)前正在執(zhí)行的函數(shù)的 Watcher
/*******************************************/
let value;
try {
value = this.getter.call();
} catch (e) {
throw e;
} finally {
/************修改的地方*******************************/
popTarget();
/*******************************************/
this.cleanupDeps();
}
return value;
}
...
}

測(cè)試

回到開(kāi)頭的場(chǎng)景,再來(lái)執(zhí)行一下:

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
text: "hello, world",
inner: "內(nèi)部",
};
observe(data);

const updateMyComponent = () => {
console.log("子組件收到:", data.inner);
};

const updateParentComponent = () => {
new Watcher(updateMyComponent);
console.log("父組件收到:", data.text);
};

new Watcher(updateParentComponent);

data.text = "hello, liang";

執(zhí)行 new Watcher(updateParentComponent); 的時(shí)候?qū)?Watcher 入棧。

進(jìn)入 updateParentComponent 函數(shù),執(zhí)行 new Watcher(updateMyComponent); 的時(shí)候?qū)?Watcher 入棧。

執(zhí)行 updateMyComponent 函數(shù),data.inner 收集當(dāng)前 Dep.target ,執(zhí)行完畢后 Watcher 出棧。

繼續(xù)執(zhí)行 updateParentComponent 函數(shù),data.text 收集當(dāng)前 Dep.target 。

此時(shí)依賴就變得正常了,data.text 會(huì)觸發(fā) updateParentComponent 函數(shù),從而輸出如下:

子組件收到: 內(nèi)部
父組件收到:hello, world
子組件收到: 內(nèi)部
父組件收到:hello, liang

總結(jié)

今天這個(gè)相對(duì)好理解一些,通過(guò)棧解決了嵌套調(diào)用的情況。

責(zé)任編輯:武曉燕 來(lái)源: windliang
相關(guān)推薦

2022-03-29 09:59:58

響應(yīng)式系統(tǒng)Vue2

2022-04-06 07:28:47

數(shù)組響應(yīng)式系統(tǒng)

2022-04-14 08:46:46

響應(yīng)式系統(tǒng)js

2022-04-03 19:27:35

Vue2響應(yīng)式系統(tǒng)

2022-04-12 10:05:18

響應(yīng)式系統(tǒng)異步隊(duì)列

2022-03-31 10:15:10

分支切換響應(yīng)式系統(tǒng)

2022-04-10 11:04:40

響應(yīng)式系統(tǒng)setdelete

2022-08-31 08:09:35

Vue2AST模版

2024-03-07 12:54:06

數(shù)據(jù)分析師企業(yè)

2024-09-02 16:10:19

vue2前端

2023-03-02 11:51:00

數(shù)據(jù)分析師企業(yè)

2019-04-25 14:20:56

數(shù)據(jù)分析套路工具

2021-05-19 14:25:19

前端開(kāi)發(fā)技術(shù)

2022-06-26 00:00:02

Vue3響應(yīng)式系統(tǒng)

2024-03-15 11:47:19

Vue2前端權(quán)限控制

2021-03-09 22:29:46

Vue 響應(yīng)式API

2023-11-19 18:53:27

Vue2MVVM

2016-10-19 20:47:55

vuevue-cli移動(dòng)端

2020-09-25 07:40:39

技術(shù)開(kāi)發(fā)選型

2020-06-09 11:35:30

Vue 3響應(yīng)式前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 91久久久久 | 男人的天堂久久 | 国产在线视频三区 | 欧美成人高清视频 | 国产精品视频一区二区三 | 中文字幕一区二区三区四区五区 | 欧美一级视频免费看 | 欧美一区精品 | 日日夜夜精品视频 | 国产福利资源在线 | 日韩一级 | 国产精品久久久久久福利一牛影视 | 中文字幕第90页 | 日韩精品在线一区二区 | 国产久 | 免费在线观看av | 亚洲精品久久久久久久久久久 | 亚洲韩国精品 | 99在线免费观看视频 | 亚洲精品久久久久久久久久久久久 | 99精品国产一区二区三区 | 精品伊人久久 | 无码一区二区三区视频 | 国产亚洲一区精品 | 伊人色综合久久天天五月婷 | 久艹av | 精品欧美一区二区三区久久久 | 久久久久久久久久久爱 | 国产成人综合在线 | 亚洲免费人成在线视频观看 | 久久蜜桃av| 91视频88av | 欧日韩在线观看 | 日韩精品一区二 | 成人午夜免费福利视频 | 久久精品国产一区二区三区不卡 | 91在线视频播放 | 午夜欧美| www.久久99| 九九热视频这里只有精品 | 久久男人天堂 |