<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 為什么要異步更新 通過前面幾個章節我們介紹,相信大家已經明白了 Vue.js 是如何在我們修改 `data` 中的數據后修改視圖了。簡單回顧一下,這里面其實就是一個“`setter -> Dep -> Watcher -> patch -> 視圖`”的過程。 假設我們有如下這么一種情況。 ``` <template> <div> <div>{{number}}</div> <div @click="handleClick">click</div> </div> </template> ``` ``` export default { data () { return { number: 0 }; }, methods: { handleClick () { for(let i = 0; i < 1000; i++) { this.number++; } } } } ``` 當我們按下 click 按鈕的時候,`number` 會被循環增加1000次。 那么按照之前的理解,每次 `number` 被 +1 的時候,都會觸發 `number` 的 `setter` 方法,從而根據上面的流程一直跑下來最后修改真實 DOM。那么在這個過程中,DOM 會被更新 1000 次!太可怕了。 Vue.js 肯定不會以如此低效的方法來處理。Vue.js在默認情況下,每次觸發某個數據的 `setter` 方法后,對應的 `Watcher` 對象其實會被 `push` 進一個隊列 `queue` 中,在下一個 tick 的時候將這個隊列 `queue` 全部拿出來 `run`( `Watcher` 對象的一個方法,用來觸發 `patch` 操作) 一遍。 ![](https://img.kancloud.cn/84/56/8456483469198b4e046cd583fc847d16_350x404.gif) 那么什么是下一個 tick 呢? ## nextTick Vue.js 實現了一個 `nextTick` 函數,傳入一個 `cb` ,這個 `cb` 會被存儲到一個隊列中,在下一個 tick 時觸發隊列中的所有 `cb` 事件。 因為目前瀏覽器平臺并沒有實現 `nextTick` 方法,所以 Vue.js 源碼中分別用 `Promise`、`setTimeout`、`setImmediate` 等方式在 microtask(或是task)中創建一個事件,目的是在當前調用棧執行完畢以后(不一定立即)才會去執行這個事件。 筆者用 `setTimeout` 來模擬這個方法,當然,真實的源碼中會更加復雜,筆者在小冊中只講原理,有興趣了解源碼中 `nextTick` 的具體實現的同學可以參考[next-tick](https://github.com/vuejs/vue/blob/dev/src/core/util/next-tick.js#L90)。 首先定義一個 `callbacks` 數組用來存儲 `nextTick`,在下一個 tick 處理這些回調函數之前,所有的 `cb` 都會被存在這個 `callbacks` 數組中。`pending` 是一個標記位,代表一個等待的狀態。 `setTimeout` 會在 task 中創建一個事件 `flushCallbacks` ,`flushCallbacks` 則會在執行時將 `callbacks` 中的所有 `cb` 依次執行。 ``` let callbacks = []; let pending = false; function nextTick (cb) { callbacks.push(cb); if (!pending) { pending = true; setTimeout(flushCallbacks, 0); } } function flushCallbacks () { pending = false; const copies = callbacks.slice(0); callbacks.length = 0; for (let i = 0; i < copies.length; i++) { copies[i](); } } ``` ## 再寫 Watcher 第一個例子中,當我們將 `number` 增加 1000 次時,先將對應的 `Watcher` 對象給 `push` 進一個隊列 `queue` 中去,等下一個 tick 的時候再去執行,這樣做是對的。但是有沒有發現,另一個問題出現了? 因為 `number` 執行 ++ 操作以后對應的 `Watcher` 對象都是同一個,我們并不需要在下一個 tick 的時候執行 1000 個同樣的 `Watcher` 對象去修改界面,而是只需要執行一個 `Watcher` 對象,使其將界面上的 0 變成 1000 即可。 那么,我們就需要執行一個過濾的操作,同一個的 `Watcher` 在同一個 tick 的時候應該只被執行一次,也就是說隊列 `queue` 中不應該出現重復的 `Watcher` 對象。 那么我們給 `Watcher` 對象起個名字吧~用 `id` 來標記每一個 `Watcher` 對象,讓他們看起來“不太一樣”。 實現 `update` 方法,在修改數據后由 `Dep` 來調用, 而 `run` 方法才是真正的觸發 `patch` 更新視圖的方法。 ``` let uid = 0; class Watcher { constructor () { this.id = ++uid; } update () { console.log('watch' + this.id + ' update'); queueWatcher(this); } run () { console.log('watch' + this.id + '視圖更新啦~'); } } ``` ## queueWatcher 不知道大家注意到了沒有?筆者已經將 `Watcher` 的 `update` 中的實現改成了 ``` queueWatcher(this); ``` 將 `Watcher` 對象自身傳遞給 `queueWatcher` 方法。 我們來實現一下 `queueWatcher` 方法。 ``` let has = {}; let queue = []; let waiting = false; function queueWatcher(watcher) { const id = watcher.id; if (has[id] == null) { has[id] = true; queue.push(watcher); if (!waiting) { waiting = true; nextTick(flushSchedulerQueue); } } } ``` 我們使用一個叫做 `has` 的 map,里面存放 id -> true ( false ) 的形式,用來判斷是否已經存在相同的 `Watcher` 對象 (這樣比每次都去遍歷 `queue` 效率上會高很多)。 如果目前隊列 `queue` 中還沒有這個 `Watcher` 對象,則該對象會被 `push` 進隊列 `queue` 中去。 `waiting` 是一個標記位,標記是否已經向 `nextTick` 傳遞了 `flushSchedulerQueue` 方法,在下一個 tick 的時候執行 `flushSchedulerQueue` 方法來 flush 隊列 `queue`,執行它里面的所有 `Watcher` 對象的 `run` 方法。 ## flushSchedulerQueue ``` function flushSchedulerQueue () { let watcher, id; for (index = 0; index < queue.length; index++) { watcher = queue[index]; id = watcher.id; has[id] = null; watcher.run(); } waiting = false; } ``` ## 舉個例子 ``` let watch1 = new Watcher(); let watch2 = new Watcher(); watch1.update(); watch1.update(); watch2.update(); ``` 我們現在 new 了兩個 `Watcher` 對象,因為修改了 `data` 的數據,所以我們模擬觸發了兩次 `watch1` 的 `update` 以及 一次 `watch2` 的 `update`。 假設沒有批量異步更新策略的話,理論上應該執行 `Watcher` 對象的 `run`,那么會打印。 ``` watch1 update watch1視圖更新啦~ watch1 update watch1視圖更新啦~ watch2 update watch2視圖更新啦~ ``` 實際上則執行 ``` watch1 update watch1 update watch2 update watch1視圖更新啦~ watch2視圖更新啦~ ``` 這就是異步更新策略的效果,相同的 `Watcher` 對象會在這個過程中被剔除,在下一個 tick 的時候去更新視圖,從而達到對我們第一個例子的優化。 我們再回過頭聊一下第一個例子, `number` 會被不停地進行 `++` 操作,不斷地觸發它對應的 `Dep` 中的 `Watcher` 對象的 `update` 方法。然后最終 `queue` 中因為對相同 `id` 的 `Watcher` 對象進行了篩選,從而 `queue` 中實際上只會存在一個 `number` 對應的 `Watcher` 對象。在下一個 tick 的時候(此時 `number` 已經變成了 1000),觸發 `Watcher` 對象的 `run` 方法來更新視圖,將視圖上的 `number` 從 0 直接變成 1000。 到這里,批量異步更新策略及 nextTick 原理已經講完了,接下來讓我們學習一下 Vuex 狀態管理的工作原理。 注:本節代碼參考[《批量異步更新策略及 nextTick 原理》](https://github.com/answershuto/VueDemo/blob/master/%E3%80%8A%E6%89%B9%E9%87%8F%E5%BC%82%E6%AD%A5%E6%9B%B4%E6%96%B0%E7%AD%96%E7%95%A5%E5%8F%8A%20nextTick%20%E5%8E%9F%E7%90%86%E3%80%8B.js)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看