petite-vue 組件的 mounted 回調發生在 nextTick() 任務之后
在使用 petite-vue 開發項目時,有一個列表視圖,每個列表項是一個自定義組件。
在向列表視圖的數組數據添加數據后,希望通過 EventBus 觸發一個事件,讓新的列表項組件 mounted 回調可以響應這個事件。
當使用 PetiteVue.nextTick() 傳入回調函數來觸發事件時,發現新的組件并沒有響應該事件。通過調試,發現對 mounted 的調用發生在 nextTick() 回調函數之后。嵌套調用兩次 PetiteVue.nextTick() 或者使用 setTimeout() 可以解決。
究其原因,是因為 petite-vue 是異步渲染 DOM 的。在當前任務循環的宏任務中修改響應式數據后,petite-vue 響應數據變化,將響應變化的行為,作為一個函數,通過 Promise 添加到當前任務循環的微任務隊列尾部。該響應行為可能會修改 DOM,對 DOM 進行更新、移除或新建。對于要新建的 DOM,如果有對應的組件,會先實例化該組件,然后才創建DOM,之后又將回調該組件 mounted 函數的行為作為一個函數添加到當前事件循環的微任務隊列尾部。
為什么不直接回調 mounted,讓 mounted 回調在 nextTcik() 添加的任務之前執行,而是在 nextTcik() 添加的任務之后才執行呢?
這是考慮到 nextTcik() 添加的任務可能還會修改數據,從而影響 DOM。
在 nextTcik() 添加的任務之后執行,mounted 回調取得的 DOM 將是 vue 對數據變化響應后的修改的最終版本。
需要注意的是,petite-vue 只有 mounted 與 unmounted 兩個生命周期回調,沒有 created。
PetiteVue.nextTick() 也是通過 Promise 添加函數到當前任務循環的微任務隊列尾部。
PetiteVue.nextTick() 在當前任務循環的宏任務中運行,它直接添加了一個微任務;petite-vue 響應數據變化的行為是一個微任務,在宏任務運行完畢后才運行,它添加的回調組件 mounted 的微任務肯定是在宏任務中添加的微任務之后。
這就是觸發 EventBus 事件的行為發生在組件監聽 EventBus 事件的行為之前的原因。
而在改變響應式數據后,嵌套調用兩次 PetiteVue.nextTick(),第一次調用發生在宏任務中,它添加一個微任務,這個微任務執行第二次 PetiteVue.nextTick(),這次又添加一個微任務隊列尾部,在新添加的微任務中觸發 EventBus 事件。
回調組件 mounted 的微任務先被添加,觸發 EventBus 事件的為微務后被添加,組件也就能響應 EventBus 事件了。
至于 setTimeout(),它將任務添加到宏任務隊列,該宏任務會在之后的事件循環中執行。而回調組件 mounted 的微任務在當前事件循環執行,組件自然能響應 EventBus 事件。

浙公網安備 33010602011771號