Vue2中异步$emit与普通异步函数执行行为差异原因探究
为什么Vue事件触发的异步逻辑和普通异步函数调用执行顺序不同?
场景1:Vue组件事件触发
点击组件内的div后,控制台输出顺序为:1 3 2 4
function foo() { return new Promise(resolve => { setTimeout(resolve, 3000); }); } Vue.component('child', { template: '<div @click="handleClick">Click</div>', methods: { async handleClick() { console.log(1); const a = await this.$emit('abc'); console.log(2); } } }); //Root Instance new Vue({ el: '#app', template: '<child @abc="handleAbc" />', data: {}, methods: { async handleAbc() { console.log(3); await foo(); console.log(4); } } })
场景2:普通异步函数调用
执行后控制台输出顺序为:1 3 4 2
function foo() { return new Promise((resolve) => { setTimeout(resolve, 3000); }); } async function foo1() { console.log(3); await foo(); console.log(4); } async function foo2() { console.log(1); await foo1(); console.log(2); } foo2();
核心差异原因
问题出在Vue的$emit方法的返回值上:
- 普通异步调用场景中,
await foo1()等待的是foo1这个异步函数返回的Promise,必须等foo1内部的await foo()执行完成、打印4之后,这个Promise才会resolve,所以foo2里的console.log(2)会在4之后执行。 - Vue场景里,
this.$emit('abc')只是同步触发绑定的handleAbc函数,但**$emit本身并不会返回handleAbc的Promise**,它的返回值是undefined。当你await undefined时,JavaScript会自动把它包装成一个已resolve的Promise,代码会立刻跳过等待,直接执行console.log(2)。而此时handleAbc里的await foo()还在等待3秒,等定时器结束后才会打印4,最终就出现了1 3 2 4的顺序。
内容的提问来源于stack exchange,提问作者user3300252
相关产品推荐
相关产品推荐

