在 JavaScript 中,异步函数通常会通过 async/await
或 Promise
处理。默认情况下,异步函数会导致后续代码等待其执行完成(即阻塞),但你可以通过不同的方法让异步函数不阻塞后续代码,直接执行函数后面的逻辑。
方法一:使用 Promise
(不使用 await
)
如果你不希望异步函数阻塞后续代码,可以不使用 await
,直接调用异步函数并处理其返回的 Promise
。
示例:
function asyncFunction() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('异步任务完成');
resolve();
}, 2000);
});
}
function main() {
console.log('开始异步任务');
asyncFunction(); // 异步任务不阻塞后续代码
console.log('异步任务已调用,继续执行后续代码');
}
main();
解释:
asyncFunction()
返回一个Promise
,但我们没有使用await
,因此不会阻塞后续代码的执行。- 输出结果:
开始异步任务
异步任务已调用,继续执行后续代码
异步任务完成
方法二:使用 setTimeout
或 setImmediate
有时你希望在事件队列中执行一些操作而不立即执行,可以使用 setTimeout
或 setImmediate
。这会将某些任务推迟到当前执行栈清空之后执行。
示例:
function asyncFunction() {
setTimeout(() => {
console.log('异步任务完成');
}, 2000);
}
function main() {
console.log('开始异步任务');
asyncFunction(); // 异步任务不会阻塞后续代码
console.log('异步任务已调用,继续执行后续代码');
}
main();
解释:
setTimeout
将asyncFunction
中的代码推迟到事件循环队列中执行,因此异步任务不会阻塞后续代码。- 输出结果:
开始异步任务
异步任务已调用,继续执行后续代码
异步任务完成
方法三:使用 async/await
但不阻塞主流程
如果你需要在异步函数中使用 await
,但又不想阻塞后续代码,你可以使用 Promise
包装 async/await
调用,并通过 then
来处理后续的逻辑。
示例:
async function asyncFunction() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('异步任务完成');
resolve();
}, 2000);
});
}
function main() {
console.log('开始异步任务');
asyncFunction().then(() => {
console.log('异步任务完成后的操作');
});
console.log('异步任务已调用,继续执行后续代码');
}
main();
解释:
asyncFunction() 返回 Promise,我们在主函数 main() 中通过 then 来处理异步操作完成后的逻辑。
输出结果:
开始异步任务
异步任务已调用,继续执行后续代码
异步任务完成
异步任务完成后的操作
总结:
Promise
: 如果不希望阻塞,可以直接调用异步函数,返回的Promise
会被自动处理,后续代码继续执行。setTimeout
/setImmediate
: 将异步任务延迟到事件循环的下一次执行,从而避免阻塞主线程。async/await
配合then
: 使用await
时通常会阻塞,但可以通过then
处理来避免阻塞后续代码的执行。
通过这些方法,你可以让异步函数在执行时不阻塞主程序的逻辑,保证代码的并行执行和流畅性。