如何让BusyHandler等待OptionHandler的异步操作完成?
如何让BusyHandler等待OptionHandler的异步操作完成?
嘿,我完全懂你的困扰——你希望BusyHandler能等到OptionHandler里的异步任务(那个2秒的setTimeout)彻底完成后再继续执行,但现在它在菜单选择完成的瞬间就结束等待了,根本没等后续的异步工作做完对吧?
问题根源
原来的逻辑里,MenuHandler返回的Promise只负责处理菜单选择结果,当SelectionHandler调用mapObj.resolve()时,这个Promise就直接resolve了。OptionHandler虽然拿到结果开始做后续异步工作,但BusyHandler只await到了“菜单选择完成”这一步,和后续的异步任务完全没有关联,自然会提前结束等待。
解决方案思路
我们需要给BusyHandler一个能跟踪OptionHandler全部工作进度的“信号”——新增一个专门的Promise,让BusyHandler等待这个Promise,而这个Promise只有在OptionHandler里所有异步任务完成后才会resolve。你自己写的第二个例子思路完全正确,下面是整理后的完整可运行代码:
<button class="showMenu">Show Menu</button> <div class="menu"> <button value=1>Option 1</button> <button value=2>Option 2</button> </div> <style> .menu { display: none; border: 1px solid black; padding: 10px; flex-flow: column; width: fit-content; } .menu.show { display: flex; } button { margin: 5px; } </style> <script> let showMenu = document.querySelector(".showMenu"), menu = document.querySelector(".menu"), busyObj = Object.create(null), mapObj = Object.create(null) ; busyObj.busyType = ''; busyObj.busyState = 0; busyObj.promise = null; busyObj.resolve = null; busyObj.reject = null; showMenu.addEventListener('mousedown', OptionHandler, false); menu.addEventListener('mousedown',BusyHandler, false); async function OptionHandler() { let option = await MenuHandler('b'); console.log(option); let d = Date.now(); console.log(`Work began at ${d}`); let p = new Promise( (resolve,reject) => { setTimeout( () => {resolve('delay resolved');}, 2000); }); await p; console.log(`Work completed at ${Date.now()-d}`); // 所有异步工作完成后,通知BusyHandler可以继续了 busyObj.resolve(); } function MenuHandler(busyType) { menu.classList.add('show'); busyObj.busyType = busyType; // 创建专门让BusyHandler等待的Promise busyObj.promise = new Promise( (resolve,reject) => { busyObj.resolve = resolve; busyObj.reject = reject; }); // 这个Promise专门用来给OptionHandler返回菜单选择结果 return new Promise( (resolve, reject) => { mapObj.resolve = resolve; mapObj.reject = reject; }); } function SelectionHandler(evt) { let e = evt.target; if ( !e.matches('.menu button, .menu button *') || !(e = e.closest('button')) ) return; menu.classList.remove('show'); // 只通知OptionHandler菜单选择完成,开始执行异步工作 mapObj.resolve(e.value); } async function BusyHandler(evt) { if ( busyObj.busyType === 'b' ) { if ( busyObj.busyState === 1) return; busyObj.busyState = 1; SelectionHandler(evt); // 现在等待的是OptionHandler完成所有工作后的信号 await busyObj.promise; console.log("BusyHandler done waiting"); busyObj.busyState= 0; } else { SelectionHandler(evt); } } </script>
关键改动说明
- 新增
busyObj对象:专门管理BusyHandler的等待状态,其中的promise用来跟踪OptionHandler的全部工作进度,只有当OptionHandler里的异步任务完成后,才调用busyObj.resolve()触发这个Promise。 - 拆分
MenuHandler的Promise职责:一个Promise负责给OptionHandler返回菜单选择结果,另一个专门给BusyHandler等待用,避免两个逻辑互相干扰。 - 简化
SelectionHandler:它只需要处理菜单选择并通知OptionHandler开始工作,不再关联BusyHandler的等待逻辑。 - 调整
BusyHandler的等待目标:现在它await的是busyObj.promise,而不是SelectionHandler的执行结果,确保能等到OptionHandler里的所有异步任务完成后再继续执行。
现在运行代码,点击菜单选项后,控制台会先显示“工作开始”,等2秒后显示“工作完成”,最后才会输出"BusyHandler done waiting",完全符合你的需求~
内容来源于stack exchange
相关产品推荐
相关产品推荐

