新闻资讯

新闻资讯 行业动态

关于Vue暴露的全局nextTick

编辑:008     时间:2020-02-25

关于Vue暴露的全局nextTick

继续来看下面的这段代码:

<div id="example">
    <div ref="test">{{test}}</div>
    <button @click="handleClick">tet</button>
</div> 
var vm = new Vue({
    el: '#example',
    data: { test: 'begin',
    },
    methods: { handleClick() {
            this.test = 'end';
            console.log('1') setTimeout(() => { // macroTask
                console.log('3')
            }, 0);
            Promise.resolve().then(function() { //microTask
                console.log('promise!')
            })
            this.$nextTick(function () {
                console.log('2')
            })
        }
    }
}) 

在Chrome下,这段代码执行的顺序的1、2、promise、3。

可能有同学会以为这是1、promise、2、3,其实是忽略了一个标志位pending。

我们回到nextTick函数return的queueNextTick可以发现:

return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve
    /*cb存到callbacks中*/
    callbacks.push(() => { if (cb) {
        try {
            cb.call(ctx)
        } catch (e) {
            handleError(e, ctx, 'nextTick')
        }
        } else if (_resolve) {
        _resolve(ctx)
        }
    }) if (!pending) {
        pending = true timerFunc()
    } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => {
        _resolve = resolve
        })
    }
} 

这里面通过对pending的判断来检测是否已经有timerFunc这个函数在事件循环的任务队列等待被执行。如果存在的话,那么是不会再重复执行的。

最后异步执行nextTickHandler时又会把pending置为false。

function nextTickHandler () {
    pending = false /*执行所有callback*/
    const copies = callbacks.slice(0)
    callbacks.length = 0 for (let i = 0; i < copies.length; i++) {
        copies[i]()
    }
} 

所以回到我们的例子:

handleClick() {
    this.test = 'end';
    console.log('1') setTimeout(() => { // macroTask
        console.log('3')
    }, 0);
    Promise.resolve().then(function() { //microTask
        console.log('promise!')
    });
    this.$nextTick(function () {
        console.log('2')
    });
} 

代码中,this.test = 'end'必然会触发watcher进行视图的重新渲染,而我们在文章的Watcher一节中就已经有提到会调用nextTick函数,一开始pending变量肯定就是false,因此它会被修改为true并且执行timerFunc。之后执行this.nextTick(fn)只是把传入的fn置入callbacks之中。此时的callbacks有两个function成员,一个是flushSchedulerQueue,另外一个就是this.$nextTick()的回调。

因此,上面这段代码中,在Chrome下,有一个macroTask和两个microTask。一个macroTask就是setTimeout,两个microTask:分别是Vue的timerFunc(其中先后执行flushSchedulerQueue和function() {console.log('2')})、代码中的Promise.resolve().then()。



原文链接:https://juejin.im/post/5e53f07d51882549036940fc
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐