「關注 前端開發社區 ,回復「 1」 即可加入 前端技術交流群,回復 「 2」 即可免費領取500G前端乾貨!
今天我們簡單了解下vue3.0的異步更新原理,了解一下effect,watchEffect的特點以及最主要queueFlush函數的實現(函數名字本意就是:排隊刷新)
effect特點
import { effect, reactive } from './reactivity';let state = reactive({ name: 'zf', age: 11 })effect(() => { console.log(state.name);})state.name = 'zf';state.name = 'jw';state.name = 'jg';每次更新狀態,都會重新運行effect。如果要是effect中包含渲染邏輯,可能會導致多次更新視圖。
watchEffect
import { effect } from "./reactivity";exportfunction watchEffect(effect, options) {return doWatch(effect, null, options);}let postFlushCbs = [];function queuePostFlushCb(cb){ postFlushCbs(cb); // 將effect放到數組中進行刷新 queueFlush();}function doWatch(source, cb, options) { // 做watchlet getter;if (isFunction(source)) { getter = () => source(); }let scheduler = (job) => queuePostFlushCb(job); const runner = effect(getter,{ // 創建一個effect lazy:true, computed: true, scheduler // 自定義scheduler }) runner();}watchEffect也是effect,只是自定義了scheduler函數
queueFlush實現
let isFlushPending = false; // 是否正在等待刷新let isFlushing = false; // 是否正在刷新const p = Promise.resolve();function nextTick(fn) {return fn ? p.then(fn) : p}functionflushPostFlushCbs(){if(postFlushCbs.length){ // 隊列有值進行隊列刷新 const cbs = [...new Set(postFlushCbs)]; postFlushCbs.length = 0;for(let i = 0; i < cbs.length;i++){ cbs[i](); } }}functionflushJobs() { isFlushPending = false; // 開始執行任務 isFlushing = true; // 正在刷新 flushPostFlushCbs(); // 刷新隊列 isFlushing = false; // 刷新完畢}functionqueueFlush() {if (!isFlushPending && !isFlushing) { isFlushPending = true; nextTick(flushJobs); // 稍後刷新任務隊列 }}nextTick本質原理就是個promise(微任務),這裡會將effect 暫存起來並進行去重之後執行。