最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2022年04月12日 20:39:09   作者:windliang  
這篇文章主要介紹了Vue2?響應(yīng)式系統(tǒng)之分支切換,文章圍繞Vue2的相關(guān)資料展開主題詳細(xì)內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下

場景

我們考慮一下下邊的代碼會輸出什么。

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: "hello, world",
    ok: true,
};
observe(data);

const updateComponent = () => {
    console.log("收到", data.ok ? data.text : "not");
};

new Watcher(updateComponent); // updateComponent 執(zhí)行一次函數(shù),輸出 hello, world

data.ok = false; // updateComponent 執(zhí)行一次函數(shù),輸出 not

data.text = "hello, liang"; // updateComponent 會執(zhí)行嗎?

我們來一步一步理清:

observer(data)

攔截了 中 和 的 ,并且各自初始化了一個 實(shí)例,用來保存依賴它們的 對象。datatextokget、setDepWatcher

image-20220331073954801

new Watcher(updateComponent)

這一步會執(zhí)行 函數(shù),執(zhí)行過程中用到的所有對象屬性,會將 收集到相應(yīng)對象屬性中的 中。updateComponentWatcherDep

image-20220331074904131

當(dāng)然這里的 其實(shí)是同一個,所以用了指向的箭頭。Watcher

data.ok = false

這一步會觸發(fā) ,從而執(zhí)行 中所有的 ,此時就會執(zhí)行一次 。setDepWatcherupdateComponent

執(zhí)行 就會重新讀取 中的屬性,觸發(fā) ,然后繼續(xù)收集 。updateComponentdatagetWatcher

image-20220331080258402

重新執(zhí)行 函數(shù) 的時候:updateComponent

const updateComponent = () => {
    console.log("收到", data.ok ? data.text : "not");
};

因?yàn)?nbsp;的值變?yōu)?nbsp;,所以就不會觸發(fā) 的 , 的 就不會變化了。data.okfalsedata.textgettextDep

而 會繼續(xù)執(zhí)行,觸發(fā) 收集 ,但由于我們 中使用的是數(shù)組,此時收集到的兩個 其實(shí)是同一個,這里是有問題,會導(dǎo)致 重復(fù)執(zhí)行,一會兒我們來解決下。data.okgetWatcherDepWacherupdateComponent

data.text = "hello, liang"

執(zhí)行這句的時候,會觸發(fā) 的 ,所以會執(zhí)行一次 。但從代碼來看 函數(shù)中由于 為 , 對輸出沒有任何影響,這次執(zhí)行其實(shí)是沒有必要的。textsetupdateComponentupdateComponentdata.okfalsedata.text

之所以執(zhí)行了,是因?yàn)榈谝淮螆?zhí)行 讀取了 從而收集了 ,第二次執(zhí)行 的時候, 雖然沒有讀到,但之前的 也沒有清除掉,所以這一次改變 的時候 依舊會執(zhí)行。updateComponentdata.textWatcherupdateComponentdata.textWatcherdata.textupdateComponent

所以我們需要的就是當(dāng)重新執(zhí)行 的時候,如果 已經(jīng)不依賴于某個 了,我們需要將當(dāng)前 從該 中移除掉。updateComponentWatcherDepWatcherDep

image-20220331081754535

問題

總結(jié)下來我們需要做兩件事情。

  • 去重, 中不要重復(fù)收集 。DepWatcher
  • 重置,如果該屬性對 中的 已經(jīng)沒有影響了(換句話就是, 中的 已經(jīng)不會讀取到該屬性了 ),就將該 從該屬性的 中刪除。DepWacherWatcherupdateComponentWatcherDep

去重

去重的話有兩種方案:

  • Dep 中的 數(shù)組換為 。subsSet
  • 每個 對象引入 , 對象中記錄所有的 的 ,下次重新收集依賴的時候,如果 的 已經(jīng)存在,就不再收集該 了。DepidWatcherDepidDepidWatcher

Vue2 源碼中采用的是方案 這里我們實(shí)現(xiàn)下:2

Dep 類的話只需要引入 即可。id

/*************改動***************************/
let uid = 0;
/****************************************/
export default class Dep {
    static target; //當(dāng)前在執(zhí)行的函數(shù)
    subs; // 依賴的函數(shù)
  	id; // Dep 對象標(biāo)識
    constructor() {
      /**************改動**************************/
        this.id = uid++;
      /****************************************/
        this.subs = []; // 保存所有需要執(zhí)行的函數(shù)
    }

    addSub(sub) {
        this.subs.push(sub);
    }
    depend() {
        if (Dep.target) {
            // 委托給 Dep.target 去調(diào)用 addSub
            Dep.target.addDep(this);
        }
    }

    notify() {
        for (let i = 0, l = this.subs.length; i < l; i++) {
            this.subs[i].update();
        }
    }
}

Dep.target = null; // 靜態(tài)變量,全局唯一

在 中,我們引入 來記錄所有的 。Watcherthis.depIdsid

import Dep from "./dep";
export default class Watcher {
  constructor(Fn) {
    this.getter = Fn;
    /*************改動***************************/
    this.depIds = new Set(); // 擁有 has 函數(shù)可以判斷是否存在某個 id
    /****************************************/
    this.get();
  }

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

  /**
     * Add a dependency to this directive.
     */
  addDep(dep) {
    /*************改動***************************/
    const id = dep.id;
    if (!this.depIds.has(id)) {
      dep.addSub(this);
    }
    /****************************************/

  }

  /**
     * Subscriber interface.
     * Will be called when a dependency changes.
     */
  update() {
    this.run();
  }

  /**
     * Scheduler job interface.
     * Will be called by the scheduler.
     */
  run() {
    this.get();
  }
}

重置

同樣是兩個方案:

  • 全量式移除,保存 所影響的所有 對象,當(dāng)重新收集 的前,把當(dāng)前 從記錄中的所有 對象中移除。WatcherDepWatcherWatcherDep
  • 增量式移除,重新收集依賴時,用一個新的變量記錄所有的 對象,之后再和舊的 對象列表比對,如果新的中沒有,舊的中有,就將當(dāng)前 從該 對象中移除。DepDepWatcherDep

Vue2 中采用的是方案 ,這里也實(shí)現(xiàn)下。2

首先是 類,我們需要提供一個 方法。DepremoveSub

import { remove } from "./util";
/*
export function remove(arr, item) {
    if (arr.length) {
        const index = arr.indexOf(item);
        if (index > -1) {
            return arr.splice(index, 1);
        }
    }
}
*/
let uid = 0;

export default class Dep {
    static target; //當(dāng)前在執(zhí)行的函數(shù)
    subs; // 依賴的函數(shù)
    id; // Dep 對象標(biāo)識
    constructor() {
        this.id = uid++;
        this.subs = []; // 保存所有需要執(zhí)行的函數(shù)
    }
		
    addSub(sub) {
        this.subs.push(sub);
    }
  /*************新增************************/
    removeSub(sub) {
        remove(this.subs, sub);
    }
  /****************************************/
    depend() {
        if (Dep.target) {
            // 委托給 Dep.target 去調(diào)用 addSub
            Dep.target.addDep(this);
        }
    }

    notify() {
        for (let i = 0, l = this.subs.length; i < l; i++) {
            this.subs[i].update();
        }
    }
}

Dep.target = null; // 靜態(tài)變量,全局唯一

然后是 類,我們引入 來保存所有的舊 對象,引入 來保存所有的新 對象。Watcherthis.depsDepthis.newDepsDep

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

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

    /**
     * Add a dependency to this directive.
     */
    addDep(dep) {
        const id = dep.id;
      /*************新增************************/
        // 新的依賴已經(jīng)存在的話,同樣不需要繼續(xù)保存
        if (!this.newDepIds.has(id)) {
            this.newDepIds.add(id);
            this.newDeps.push(dep);
            if (!this.depIds.has(id)) {
                dep.addSub(this);
            }
        }
      /****************************************/
    }

    /**
     * Clean up for dependency collection.
     */
  	/*************新增************************/
    cleanupDeps() {
        let i = this.deps.length;
        // 比對新舊列表,找到舊列表里有,但新列表里沒有,來移除相應(yīng) Watcher
        while (i--) {
            const dep = this.deps[i];
            if (!this.newDepIds.has(dep.id)) {
                dep.removeSub(this);
            }
        }

        // 新的列表賦值給舊的,新的列表清空
        let tmp = this.depIds;
        this.depIds = this.newDepIds;
        this.newDepIds = tmp;
        this.newDepIds.clear();
        tmp = this.deps;
        this.deps = this.newDeps;
        this.newDeps = tmp;
        this.newDeps.length = 0;
    }
  	/****************************************/
    /**
     * Subscriber interface.
     * Will be called when a dependency changes.
     */
    update() {
        this.run();
    }

    /**
     * Scheduler job interface.
     * Will be called by the scheduler.
     */
    run() {
        this.get();
    }
}

測試

回到開頭的代碼

import { observe } from "./reactive";
import Watcher from "./watcher";
const data = {
    text: "hello, world",
    ok: true,
};
observe(data);

const updateComponent = () => {
    console.log("收到", data.ok ? data.text : "not");
};

new Watcher(updateComponent); // updateComponent 執(zhí)行一次函數(shù),輸出 hello, world

data.ok = false; // updateComponent 執(zhí)行一次函數(shù),輸出 not

data.text = "hello, liang"; // updateComponent 會執(zhí)行嗎?

此時 修改的話就不會再執(zhí)行 了,因?yàn)榈诙螆?zhí)行的時候,我們把 中 里的 清除了。data.textupdateComponentdata.textDepWatcher

總結(jié)

今天這個主要就是對響應(yīng)式系統(tǒng)的一點(diǎn)優(yōu)化,避免不必要的重新執(zhí)行。所做的事情就是重新調(diào)用函數(shù)的時候,把已經(jīng)沒有關(guān)聯(lián)的 去除。Watcher

不知道看到這里大家有沒有一個疑問,我是一直沒想到說服我的點(diǎn),歡迎一起交流:

在解決去重問題上,我們是引入了 ,但如果直接用 其實(shí)就可以。在 類中是用 來存 ,用數(shù)組來存 對象,為什么不直接用 來存 對象呢?idsetWatcherSetidDepSetDep

到此這篇關(guān)于Vue2 響應(yīng)式系統(tǒng)之分支切換的文章就介紹到這了,更多相關(guān)Vue2分支切換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue通過vue-router實(shí)現(xiàn)頁面跳轉(zhuǎn)的全過程

    Vue通過vue-router實(shí)現(xiàn)頁面跳轉(zhuǎn)的全過程

    這篇文章主要介紹了Vue通過vue-router實(shí)現(xiàn)頁面跳轉(zhuǎn)的操作步驟,文中有詳細(xì)的代碼示例和圖文供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,感興趣的朋友可以參考下
    2024-04-04
  • 探究Vue.js 2.0新增的虛擬DOM

    探究Vue.js 2.0新增的虛擬DOM

    vue.js 2.0大家對此并不陌生吧。最令人興奮的是更新頁面的"虛擬DOM"的加入。那么對于虛擬 DOM 可以做什么呢?今天小編通過本文給大家解答下
    2016-10-10
  • vue router使用query和params傳參的使用和區(qū)別

    vue router使用query和params傳參的使用和區(qū)別

    本篇文章主要介紹了vue router使用query和params傳參的使用和區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • vue-router懶加載速度緩慢問題及解決方法

    vue-router懶加載速度緩慢問題及解決方法

    這篇文章主要介紹了vue-router懶加載速度緩慢問題及解決方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • vue3引入Element-plus的詳細(xì)步驟記錄

    vue3引入Element-plus的詳細(xì)步驟記錄

    Element Plus是為適配Vue3而對Element UI進(jìn)行重構(gòu)后產(chǎn)生的前端組件庫,包含豐富的基礎(chǔ)組件,下面這篇文章主要給大家介紹了關(guān)于vue3引入Element-plus的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • 在vue中解決提示警告 for循環(huán)報錯的方法

    在vue中解決提示警告 for循環(huán)報錯的方法

    今天小編就為大家分享一篇在vue中解決提示警告 for循環(huán)報錯的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • Element的Message彈窗重復(fù)彈出問題解決

    Element的Message彈窗重復(fù)彈出問題解決

    本文主要介紹了Element的Message彈窗重復(fù)彈出,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 為vue-router懶加載時下載js的過程中添加loading提示避免無響應(yīng)問題

    為vue-router懶加載時下載js的過程中添加loading提示避免無響應(yīng)問題

    這篇文章主要介紹了為vue-router懶加載時下載js的過程中添加loading提示避免無響應(yīng)問題,需要的朋友可以參考下
    2018-04-04
  • Vue中的性能優(yōu)化方案

    Vue中的性能優(yōu)化方案

    本文主要介紹了Vue中的性能優(yōu)化方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 基于Vue uniapp實(shí)現(xiàn)貪吃蛇游戲

    基于Vue uniapp實(shí)現(xiàn)貪吃蛇游戲

    貪吃蛇游戲想必是很多70、80后的回憶,一直到現(xiàn)在也深受大家的喜歡。本文將利用Vue+uniapp實(shí)現(xiàn)這一經(jīng)典的游戲,感興趣的可以了解一下
    2022-04-04

最新評論

沁源县| 来宾市| 永仁县| 高邮市| 临湘市| 延川县| 曲周县| 凤城市| 东宁县| 朝阳市| 密山市| 股票| 仙居县| 中方县| 惠东县| 永胜县| 安顺市| 错那县| 宜昌市| 偃师市| 乌拉特前旗| 乌苏市| 都江堰市| 洪雅县| 禹城市| 隆尧县| 麻栗坡县| 江津市| 太谷县| 荥经县| 武穴市| 广宗县| 仁化县| 门源| 鲁山县| 平利县| 惠东县| 车致| 萨嘎县| 阳曲县| 湖南省|