如何让不可修改的系列函数等待事件处理器触发后再依次执行?
解决方案:用Promise包装+Async/Await串行执行动态函数列表
嘿,这个需求我太懂了!之前做动态流程编排的时候也碰到过类似的情况——不能修改原有函数,还得让它们按顺序等事件触发完再往下走,而且每次的函数顺序、数量都不固定,硬写链式调用完全行不通对吧?
核心思路其实就是把每个不可修改的函数和它对应的事件触发,包装成一个Promise,然后用async/await来串行执行这些Promise,不管你的函数列表怎么变,都能自动按顺序等待上一个事件触发后再执行下一个。
具体实现步骤
首先,先模拟一下你说的那些“无法修改的函数”(它们的逻辑是创建事件处理器,触发后才完成任务):
// 示例:不可修改的函数,每个都会创建一个事件处理器 function doFirstThing() { const triggerBtn = document.createElement('button'); triggerBtn.textContent = '点我完成第一步'; document.body.appendChild(triggerBtn); // 原函数内部的事件处理器 triggerBtn.addEventListener('click', () => { console.log('第一步事件触发!'); triggerBtn.remove(); }); } function doSecondThing() { const triggerBtn = document.createElement('button'); triggerBtn.textContent = '点我完成第二步'; document.body.appendChild(triggerBtn); triggerBtn.addEventListener('click', () => { console.log('第二步事件触发!'); triggerBtn.remove(); }); } function doThirdThing() { // 假设这个函数触发的是自定义事件,而不是DOM点击 setTimeout(() => { document.dispatchEvent(new CustomEvent('thirdTaskDone')); }, 1000); }
接下来,我们写一个通用的包装函数,把这些函数转换成返回Promise的版本,关键是捕获到事件触发的时机:
/** * 包装不可修改的函数,返回一个Promise,事件触发时resolve * @param {Function} fn - 要执行的不可修改函数 * @param {EventTarget} eventTarget - 事件触发的目标元素/对象 * @param {string} eventType - 要监听的事件类型 * @param {Function} [eventFilter] - 可选,过滤事件(比如区分不同函数触发的同类型事件) */ function wrapFunction(fn, eventTarget, eventType, eventFilter) { return new Promise((resolve) => { // 先执行原函数,让它创建事件处理器 fn(); // 监听目标事件,触发时resolve Promise const handler = (event) => { // 如果有过滤条件,先判断是不是当前函数触发的事件 if (eventFilter && !eventFilter(event)) return; resolve(); // 移除监听,避免内存泄漏 eventTarget.removeEventListener(eventType, handler); }; eventTarget.addEventListener(eventType, handler); }); }
最后,用async/await来串行执行你的动态函数列表:
async function runDynamicSequence(taskList) { for (const task of taskList) { // 等待当前任务的事件触发完成 await wrapFunction(task.fn, task.target, task.eventType, task.filter); console.log('当前任务完成,开始下一个'); } console.log('所有任务执行完毕!'); } // 示例调用1:按 第一步→第二步 的顺序执行 runDynamicSequence([ { fn: doFirstThing, target: document.body, eventType: 'click' }, { fn: doSecondThing, target: document.body, eventType: 'click' } ]); // 示例调用2:按 第三步→第一步 的顺序执行(完全自定义顺序) // runDynamicSequence([ // { fn: doThirdThing, target: document, eventType: 'thirdTaskDone' }, // { fn: doFirstThing, target: document.body, eventType: 'click' } // ]);
关键注意点
- 事件匹配:如果多个函数触发的是同类型事件(比如都是click),你可以给自定义事件加
detail标识,或者通过元素特征(比如class)来过滤,避免误触发。比如给doFirstThing的按钮加个class,然后在eventFilter里判断event.target.classList.contains('first-task-btn')。 - 内存泄漏:一定要在事件触发后移除监听,不然每次执行都会残留监听函数。
- 自定义事件适配:如果原函数触发的是自定义事件(不是DOM事件),只需要把eventTarget改成对应的触发对象(比如document、window),eventType改成自定义事件名即可。
这个方案完全不需要修改原有函数的代码,而且不管你的函数列表顺序、数量怎么变,只需要传入对应的任务配置就能按顺序执行,完美适配你的需求!
内容的提问来源于stack exchange,提问作者Marked as Duplicate
相关产品推荐
相关产品推荐

