为何async函数在addEventListener与手动调用时表现不同?
为什么同一async函数在手动调用和按钮点击时表现不同?
这个问题的核心在于Promise的状态一旦确定就会被缓存,不会重复执行异步逻辑,结合你的代码场景,两种调用方式的差异可以拆解为:
1. 手动调用时的10秒延迟
你的handlePromises函数在手动调用时,应该是在函数内部每次都创建了新的Promise实例,类似这样:
async function handlePromises() { // 每次调用函数,都会新建两个Promise,各自触发5秒计时 const promise1 = new Promise(resolve => { setTimeout(() => { console.log('Promise1 resolved'); resolve(); }, 5000); }); const promise2 = new Promise(resolve => { setTimeout(() => { console.log('Promise2 resolved'); resolve(); }, 5000); }); // await是串行执行:先等promise1完成(5秒),再等promise2完成(又5秒),总共10秒 await promise1; await promise2; } // 页面刷新时立即调用,触发全新的异步流程 handlePromises();
因为两个Promise是串行await的,所以总耗时是两个5秒相加,最终10秒后依次输出结果。
2. 按钮点击时的5秒+立即输出
而绑定按钮点击事件时,你的Promise实例应该是在函数外部定义的(页面加载时就已经创建并开始计时),类似这样:
// 页面加载时就创建Promise,立即开始5秒计时 const promise1 = new Promise(resolve => { setTimeout(() => { console.log('Promise1 resolved'); resolve(); }, 5000); }); const promise2 = new Promise(resolve => { setTimeout(() => { console.log('Promise2 resolved'); resolve(); }, 5000); }); async function handlePromises() { // 这里await的是已经存在的Promise实例 await promise1; await promise2; } // 点击按钮时调用函数 button.addEventListener('click', handlePromises);
- 第一次点击按钮:此时两个Promise已经在页面加载时运行了一段时间,等到5秒后同时完成,所以控制台会一起输出结果(因为两个定时器是同时启动的)。
- 再次点击按钮:此时两个Promise的状态已经是
resolved了,Promise的状态是不可逆的,await会直接获取缓存的结果,不会重新触发定时器,所以立即输出内容。
总结
两种场景的本质差异是:
- 手动调用时,每次执行函数都会创建全新的Promise实例,触发全新的异步计时,串行await导致总耗时累加。
- 按钮点击时,复用了提前创建的Promise实例,第一次点击时异步操作已经在进行,后续点击时Promise已经处于resolved状态,无需等待。
内容的提问来源于stack exchange,提问作者Daniel Vanum
相关产品推荐
相关产品推荐

