<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在 開發中肯定存在元件巢狀元件的情況,類似於下邊的樣子。Vue
<!-- parent-component --> <div> <my-component :text="inner"></my-component> {{ text }} <div> <!-- my-component--> <div>{{ text }}</div>
回到我們之前的響應式系統,模擬一下上邊的情況:
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
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
上邊的問題出在我們儲存當前正在執行 時候使用的是單個變數 。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; } ... }
回到開頭的場景,再來執行一下:
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響應式系統之巢狀的文章就介紹到這了,更多相關Vue2 巢狀內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45