闭包实现链式异步流水线的核心是通过IIFE创建私有作用域封装tasks数组,每个then/catch/finally返回新实例并累积任务,run方法按序await执行;优势在于真正私有状态、天然不可变链与无this绑定问题。

用闭包实现支持链式调用的异步任务流水线,核心是让每个方法返回一个新的、封装了当前状态(如待执行任务队列)的对象,同时保持对私有上下文(如 tasks 数组、是否已启动等)的封闭访问。这样既能避免污染全局,又能自然串联 .then() 风格的操作。
设计一个可累积任务的闭包工厂
闭包的作用是保存内部状态(比如任务列表),并暴露一组方法来追加异步操作,而不暴露原始数据。关键点是每次调用 then 或类似方法时,不立即执行,而是把函数推入队列,并返回新实例(保持链式):
- 用立即执行函数(IIFE)创建私有作用域
- 内部维护一个
tasks = []存储待执行的异步函数(每个接收前一步结果,返回 Promise) - 每个公开方法(如
then、catch、finally)都返回新的流水线实例,复用同一套逻辑 - 提供
run(input)或start()触发实际执行,按序 await 每个 task
实现基础链式流水线类(闭包版)
下面是一个轻量、无依赖的实现示例:
const AsyncPipeline = (function () {
// 工厂函数:返回新流水线实例
return function () {
let tasks = [];
<pre class="brush:php;toolbar:false;">function addTask(fn) {
tasks.push(fn);
return {
then: addTask,
catch: function (onReject) {
tasks.push((prev) => Promise.resolve(prev).catch(onReject));
return { then: addTask, catch, finally: finalizer };
},
finally: finalizer
};
}
function finalizer(fn) {
tasks.push(async (prev) => {
try {
await Promise.resolve(prev);
} finally {
await Promise.resolve(fn());
}
});
return { then: addTask, catch, finally: finalizer };
}
return {
then: addTask,
catch: function (onReject) {
tasks.push((prev) => Promise.resolve(prev).catch(onReject));
return { then: addTask, catch, finally: finalizer };
},
finally: finalizer,
run: async function (input) {
let result = input;
for (const task of tasks) {
result = await task(result);
}
return result;
}
};}; })();
// 使用示例: AsyncPipeline() .then(x => new Promise(r => setTimeout(() => r(x + 1), 100))) .then(x => Promise.resolve(x * 2)) .catch(err => console.error('Error:', err)) .finally(() => console.log('Done')) .run(10) .then(console.log); // 输出: 22
增强实用性:支持初始值、错误跳过与并发控制
真实场景中常需更灵活的控制。可在闭包内扩展状态位和配置项:
立即学习“Java免费学习笔记(深入)”;
- 添加
withInitial(value)预设起始输入,避免每次run()传参 - 引入
skipOnError(true)让失败任务不中断后续(内部用.catch(() => undefined)吞异常) - 提供
parallel(...fns)方法,将多个异步函数并发执行并合并结果(用Promise.all) - 所有扩展方法仍返回新实例,保证链式纯净性
为什么必须用闭包?不用 class 行不行?
可以用 class,但闭包在此场景有明确优势:
- 真正私有状态:
tasks无法被外部修改,class 的 #private 字段虽也私有,但语法稍重且兼容性受限 - 天然不可变链:每次
.then()返回的是全新闭包实例,旧实例状态冻结,避免意外共享 - 更易组合:多个流水线可嵌套或拼接(例如
p1.run().then(x => p2.then(...).run(x))),闭包边界清晰 - 无 this 绑定烦恼:所有方法都是普通函数引用,不依赖调用上下文


















