JavaScript异步串行执行:从回调到Async/Await的完整实现
本文深入解析JavaScript中异步任务的串行执行方案。通过对比直接调用、回调嵌套、Promise链式调用及Async/Await语法,详细阐述不同场景下的实现逻辑。此外,文章还提供了一种基于next回调机制的自定义串行执行器实现,支持动态任务数量及参数传递,帮助开发者掌握异步流程控制的多种技巧。
异步串行执行概述
本文主要探讨如何按顺序依次执行一组异步任务。为了直观展示,我们先使用setTimeout函数来模拟几个异步操作场景:
let taskA = () => setTimeout(() => console.log('run task A'), 100);
let taskB = () => setTimeout(() => console.log('run task B'), 50);
let taskC = () => setTimeout(() => console.log('run task C'), 150);
直接运行
直接调用的局限性
taskA(); taskB(); taskC();
上述代码直接执行时,无法保证任务A、B、C按照预期的顺序完成,因为setTimeout是异步非阻塞的。
首先介绍最基础的传统实现方式,即通过回调函数机制,在当前任务执行完毕后,再触发下一个任务的执行:
基于回调的传统实现
let taskA = setTimeout(() => {
console.log('run task A');
taskB();
}, 100);
let taskB = setTimeout(() => {
console.log('run task B');
taskC();
}, 50);
let taskC = setTimeout(() => {
console.log('run task B');
}, 150);
第二种方案是将每个异步操作封装为返回Promise对象的函数,利用Promise的then方法进行链式调用,从而实现串行执行:
基于Promise链式调用
let taskA = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('run task A');
resolve();
}, 100);
})
let taskB = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('run task B');
resolve();
}, 50);
})
let taskC = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('run task C');
resolve();
}, 150);
})
function runTasks2() {
console.log('tasks 2');
taskA().then(taskB).then(taskC);
}
如果任务的数量不固定或动态变化,可以采用以下遍历方式来实现串行执行:
动态任务数量的处理
function runTasks3(tasks) {
console.log('tasks 3');
let pro = tasks[0]();
for (let i = 1; i < tasks.length; i++) {
pro.then(tasks[i]);
}
}
借助ES7引入的async和await关键字,我们可以对上述逻辑进行更简洁的重写:
Async/Await语法优化
async function runTasks3_1(tasks) {
for (let i = 0; i < tasks.length; i++) {
await tasks[i]();
}
}
在文章末尾,我们将手动实现一个通用的串行执行器,用于处理一组需要按序执行的任务:
自定义串行执行器实现
function async(tasks) {
const count = tasks.length;
let index = 0;
const next = () => {
if (index >= count) return;
const task = tasks[index++];
task(next);
}
next(0);
}
该执行器的具体调用方式如下所示:
async([
next => setTimeout(() => { console.log('taskA ...'); next() }, 100),
next => setTimeout(() => { console.log('taskB ...'); next() }, 50),
next => setTimeout(() => { console.log('taskC ...'); next() }, 30)
]);
在每个子任务的内部,通过调用next函数来显式触发并执行下一个子任务。
在实际应用场景中,可能会涉及任务间的数据传递,即前一个任务的执行结果需要作为参数传递给下一个任务。针对这种情况,只需对上述示例代码稍作调整即可实现。
至此,关于JavaScript异步流程控制中串行执行的详细解析已完成。如需了解更多JavaScript串行执行相关内容,建议查阅本站过往文章或继续浏览后续相关教程,感谢大家的支持!
JS处理含Emoji或中文的字符串转数组乱码问题
2026-11-05 16:12:28
JS怎么使用展开运算符合并对象
2026-11-05 14:42:18
ES6+环境下判断JS对象为空的简洁写法
2026-11-05 12:12:23
怎么通过replacer函数自定义JS中JSON的格式化输出
2026-11-05 11:19:44
JS正则表达式基础:字面量与RegExp构造函数的区别及常用元字符
2026-11-05 11:16:58
