vue中promise和DOM渲染的先后顺序是怎样的呢?

看下例子,我搞不懂为啥promise没有按照预期那样

<template>
<span ref="a">{{a}}</span>
<button @click="click">按钮</button>
</template>
<script>
export default {
    data() {
        return {
            a: 1
        }
    },
    methods: {
        click() {
            this.a = 2;
            console.log(this.$refs.a.innerHTML); // 预期输出1
            Promise.resolve().then(() => {
                 // 预期输出1,实际输出2。
                console.log(this.$refs.a.innerHTML);
            })
        }
    }
}
</script>

在这个简单的实例中,我使用promise来输出a中的内容,理论上 promise 是微任务,在本轮宏任务完成后进行处理,然后才是渲染页面,所以我预期输出1,可是为什么确输出了2呢?是 vue 有另外的处理逻辑吗?

阅读 6.3k
6 个回答

这个问题很简单,跟nextTick执行有关。要想先输出1,在 this.a = 2 之前写promise即可

            click() {// 预期输出1
                Promise.resolve().then(() => {
                     // 预期输出1,实际输出1。
                    console.log('1 - ',this.$refs.a.innerHTML);
                })
                this.a = 2;
                console.log('2 - ', this.$refs.a.innerHTML); // 预期输出1
                Promise.resolve().then(() => {
                     // 预期输出1,实际输出2。
                    console.log('3 - ', this.$refs.a.innerHTML);
                })
            }
            // 2 - 1  
            // 1 - 1  
            // 3 - 2
        

因为 nextTick 的执行是从一个队列里拿cb(回调函数),click()函数中, this.a = 2会生成一个异步cb,push到nextTick的队列里,后来又有一个promise,又push到nextTick的队列里;赋值的cb在promise前面,所以第二个promise执行的时候,拿到的是修改后的值。

因为在 vue 中视图的渲染也是微任务啊。

console的实际上是一个堆内存的指向,在chrome里显示的是那个指向,并不是当前值,你可以用JSON.string或deepclone来不受下面语句的影响

执行this.a = 2的时候,会先执行watcher,然后走nextTick,更新完dom后,然后才是promise,所以能取到正确的值。

赞同楼上的,我刚刚看了一篇文章
vue的nextTick既可以是微任务,也可以是宏任务
在vue v2.4 后
默认是微任务,下面是文章链接
https://www.cnblogs.com/mengf...

新手上路,请多包涵

this.a = 2 执行的时候会触发set,调用watcher,然后_render、_update、patch更新dom节点。这个过程是通过 nextTick 调用的,所以也会放到微任务队列,并且在console.log('3 - ', this.$refs.a.innerHTML)之前,所以输出2没问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题