JavaScript异步串行执行:从回调到Async/Await的完整实现

作者:拾光

时间:2026-10-23

浏览:249

本文深入解析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串行执行相关内容,建议查阅本站过往文章或继续浏览后续相关教程,感谢大家的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章