如何在多个JavaScript耗时函数执行完毕后触发回调且避免嵌套?
嗨,这个问题问得特别好!完全没必要用多层嵌套回调来折腾自己——JavaScript发展到现在,已经有好几种更优雅、更易读的方式来处理「等待多个异步任务全部完成后再执行后续逻辑」的需求,咱们来具体聊聊:
方法1:用
Promise.all()实现并行等待 Promise.all()是专门用来处理多个异步任务并行等待的API:它接收一个Promise数组,只有当数组里所有Promise都成功完成时,才会进入.then()回调;如果有任何一个Promise失败,就会直接进入.catch()处理错误。
假设你的两个耗时函数是返回Promise的异步函数(如果原来不是,后面会说怎么改造),可以这么写:
// 先定义返回Promise的异步耗时函数 function thisTakes2Seconds() { return new Promise(resolve => { setTimeout(() => resolve('来自2秒任务的结果'), 2000); }); } function thisTakes5Seconds() { return new Promise(resolve => { setTimeout(() => resolve('来自5秒任务的结果'), 5000); }); } // 等待所有任务完成后执行post请求 Promise.all([thisTakes2Seconds(), thisTakes5Seconds()]) .then(results => { const data = { x: results[0], // 第一个任务的结果 y: results[1] // 第二个任务的结果 }; http.post(data); }) .catch(error => { // 处理任意一个任务失败的情况 console.error('某个异步任务出错了:', error); });
方法2:用
async/await写出同步风格的异步代码 如果你觉得.then()的链式写法还是有点别扭,async/await绝对是你的福音——它是Promise的语法糖,能让异步代码看起来和同步代码一样直观:
// 复用上面定义的两个Promise函数 async function handleAllTasks() { try { // 用解构赋值直接拿到两个任务的结果,这里是并行执行的哦 const [xResult, yResult] = await Promise.all([thisTakes2Seconds(), thisTakes5Seconds()]); const data = { x: xResult, y: yResult }; http.post(data); } catch (error) { console.error('任务执行出错:', error); } } // 调用这个异步函数 handleAllTasks();
如果你的函数是老式回调风格怎么办?
如果你的thisTakes2Seconds和thisTakes5Seconds是基于回调的老式函数(比如接收一个(err, result)的回调参数),可以先把它们包装成Promise:
// 把回调式函数包装成Promise function promisifyTask(taskFn) { return new Promise((resolve, reject) => { taskFn((err, result) => { if (err) reject(err); else resolve(result); }); }); } // 之后就可以用上面的方法来处理了 const task1 = promisifyTask(thisTakes2SecondsCallbackStyle); const task2 = promisifyTask(thisTakes5SecondsCallbackStyle); Promise.all([task1, task2]).then(results => { const data = { x: results[0], y: results[1] }; http.post(data); });
总的来说,多层嵌套回调(也就是大家常说的「回调地狱」)是早期JavaScript的无奈选择,现在有了Promise和async/await,完全可以写出清晰、易维护的异步代码,再也不用嵌套来嵌套去啦~
内容的提问来源于stack exchange,提问作者Juicy
相关产品推荐
相关产品推荐

