旧版Node.js无Promise时用async库实现串并行混合异步任务
问题根因
代码无法执行到任务3、4的核心原因是async库的执行规则:所有传入async流程的任务函数,必须在任务执行完成后主动调用入参提供的回调函数,通知async当前任务结束,流程才会向后推进。
你的代码中外层async.series的第一个任务块(负责执行任务1、2),在嵌套的串行流程跑完后,没有调用外层任务传入的回调,导致async始终判定第一个任务块未完成,永远不会进入下一个并行任务块。
另外你的readFile1函数错误分支调用回调后没有终止执行,会出现错误场景下重复调用回调的隐患,也需要修复。
修复后代码
const async = require('async'); const fs = require('fs'); const readFile1 = (name, callback) => { fs.readFile(name, 'utf-8', (err, data) => { if (err) { // 错误回调触发后直接return,避免重复调用回调 return callback(err); } console.log(data); callback(null, data); }); } async.series([ // 第一个任务块:串行执行任务1、任务2 function(taskBlockCb) { async.series([ function(cb) { readFile1('./1.txt', cb); }, function(cb) { readFile1('./2.txt', cb); }, ], function(err, results) { console.log('series ', results); // 关键:当前任务块执行完毕,必须调用外层传入的块回调,通知async推进流程 taskBlockCb(err, results); }); }, // 第二个任务块:并行执行任务3、任务4 function(taskBlockCb) { async.parallel([ function(cb) { readFile1('./3.txt', cb); }, function(cb) { readFile1('./4.txt', cb); }, ], function(err, results) { console.log('parallel ', results); // 执行完调用块回调,标记当前任务块结束 taskBlockCb(err, results); }); } ], function(err, allResults) { // 全流程最终回调 if (err) { return console.error('流程执行异常:', err); } console.log('所有任务执行完成,结果:', allResults); });
简化写法
这个串并行混合的流程不需要额外嵌套内层async.series,可以直接把串行任务平铺到外层series数组中,代码更简洁:
async.series([ // 任务1 cb => readFile1('./1.txt', cb), // 任务2 cb => readFile1('./2.txt', cb), // 任务3、4并行块 blockCb => { async.parallel([ cb => readFile1('./3.txt', cb), cb => readFile1('./4.txt', cb) ], blockCb) } ], (err, res) => { if (err) return console.error(err); console.log('全部任务执行完成', res); })
编写注意事项
- 所有传给async的任务函数,无论执行成功还是失败,最终必须调用入参提供的回调,否则整个流程会永久卡住
- 回调的第一个参数固定传错误对象,无错误时必须传
null,第二个及之后的参数传任务的返回结果 - 错误分支调用回调后记得加
return终止后续逻辑,避免同个任务多次调用回调触发报错
内容的提问来源于stack exchange,提问作者Blured Derulb
相关产品推荐
相关产品推荐

