vue异步更新策略

169 阅读1分钟

nextTick只是异步更新策略的一环,不能把1nextTick等同于异步更新

1.实现队列机制

当触发了watcher.update方法后,通过queueWatcher把触发的更新都存储在一个数组中,在nextTick异步函数的回调中遍历这些更新操作,依次执行,从而达到异步批量更新的逻辑。

update(){
    queueWatcher(this);
}


import {
    nextTick
} from '../util/next-tick'
let has = {};
let queue = [];

function flushSchedulerQueue() {
    for (let i = 0; i < queue.length; i++) {
        let watcher = queue[i];
        watcher.run()
    }
    queue = [];
    has = {}
}
let pending = false
export function queueWatcher(watcher) {
    const id = watcher.id;
    if (has[id] == null) {
        has[id] = true;
        queue.push(watcher);
        if(!pending){
            nextTick(flushSchedulerQueue)
            pending = true;
        }
    }
}

2. nextTick实现原理

nextTick是一个根据兼容性不断降级的微任务或者宏任务,值的注意的是在它的内部也有一个数组用来存储回调函数,从而实现用户自己调用的nextTick能够访问到最新的dom

let callbacks = [];
function flushCallbacks() {
    callbacks.forEach(cb => cb());
}
let timerFunc;
if (Promise) { // then方法是异步的
    timerFunc = () => {
        Promise.resolve().then(flushCallbacks)
    }
}else if (MutationObserver) { // MutationObserver 也是一个异步方法
    let observe = new MutationObserver(flushCallbacks); // H5的api
    let textNode = document.createTextNode(1);
    observe.observe(textNode, {
        characterData: true
    });
    timerFunc = () => {
        textNode.textContent = 2;
    }
}else if (setImmediate) {
    timerFunc = () => {
        setImmediate(flushCallbacks)
    }
}else{
    timerFunc = () => {
        setTimeout(flushCallbacks, 0);
    }
}
export function nextTick(cb) {
    callbacks.push(cb);
    timerFunc();
}