async-flow 是一个基于 rxjs的异步逻辑处理库.它的目的是用一种声明式的方式定义异步逻辑,并且尽可能的隐藏 rxjs 操作符的复杂性.
初始值是 buildFlow 的第一个参数,后续每个 flow 执行完毕后将其结果放置在 context 上. 后面的 flow 有能力访问到之前 flow 产生的结果.
flow 使用 flowConfig 来定义一个异步逻辑,一个 flowConfig 是一个包含如下字段的对象:
- name(必填): string 这个异步逻辑的名称,执行完毕后将结果注入到 context
- flow(必填): (context)=> Promise|flow|Observable 这个异步逻辑的主体
- map(可选): (result,context) => result
- children(可选) : 子 flow(参考下面的例子)
定义 flowConfig
之后,使用 buildFlow
创建 flow. 之后调用 flow.subscribe
订阅 flow 的结果.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=basic-usage.ts
import { buildFlow } from "@tomyail/async-flow";
// basic usage
const flowConfig = {
//flow 的名称
name: "asyncTask1",
//异步逻辑
flow: context => {
return Promise.resolve(1);
}
};
//build async flow
const asyncFlow = buildFlow({}, [flowConfig]);
//运行 flow
asyncFlow.subscribe(context => {
console.log(context);
// {
// asyncTask1: 1
// }
});
flowConfig 的 map 方法可以用来处理 flow 异步响应后的逻辑.通常在这里编写一些数据转换逻辑(比如把 server 返回的 jsonapi 数据做一次预处理)
以下例子在上一个例子的基础上对返回结果做了一次+100 的操作.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=basic_usage_with_map.ts
import { buildFlow } from "@tomyail/async-flow";
// basic usage
const flowConfig = {
//flow 的名称
name: "asyncTask1",
//异步逻辑
flow: context => {
return Promise.resolve(1);
},
//将 flow 的结果+100
map: (result, context) => result + 100
};
//build async flow
const asyncFlow = buildFlow({}, [flowConfig]);
//运行 flowb
asyncFlow.subscribe(context => {
console.log(context);
// {
// asyncTask1: 101
// }
});
如果 buildFlow
的第二个参数是 flowConfig 数组,那么数组里面的每一项将按照数组的先后次序依次执行.后执行的异步逻辑可以通过 context 拿到它之前异步逻辑的结果.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=queue_flow.ts
import { buildFlow } from "@tomyail/async-flow";
// basic usage
const asyncTask1 = {
//flow 的名称
name: "asyncTask1",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask1");
}
};
const asyncTask2 = {
//flow 的名称
name: "asyncTask2",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask2" + context.asyncTask1);
}
};
//build async flow
const asyncFlow = buildFlow({}, [asyncTask1,asyncTask2]);
//运行 flowbb
asyncFlow.subscribe(context => {
console.log(context);
// {asyncTask1: "asyncTask1", asyncTask2: "asyncTask2asyncTask1"}
});
当 buildFlow
的第二个参数是 flowConfig 对象时. 这个对象的每一项都会并行执行.
所以相邻的异步逻辑无法获取其他异步逻辑的结果. 并行定义 flow 时,flowConfig 哈希的每一项的 key 必须和 flowConfig 的 name 一致,否则会报错.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=parallel_flow.ts
import { buildFlow } from "@tomyail/async-flow";
// basic usage
const asyncTask1 = {
//flow 的名称
name: "asyncTask1",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask1");
}
};
const asyncTask2 = {
//flow 的名称
name: "asyncTask2",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask2" + context.asyncTask1);
}
};
//build async flow
const asyncFlow = buildFlow({}, { asyncTask1, asyncTask2 });
//运行 flowbb
asyncFlow.subscribe(context => {
console.log(context);
// {asyncTask1: "asyncTask1", asyncTask2: "asyncTask2undefined"}
});
每个 flowConfig 可以定义 children 属性,其类型可以是数组或者flowConfig 哈希.在其父异步逻辑执行完毕后,将会执行 children flow.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=children_flow.ts
import { buildFlow } from "@tomyail/async-flow";
// basic usage
const asyncTask1 = {
//flow 的名称
name: "asyncTask1",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask1");
},
children: [
{
name: "asyncTask1_child1", //异步逻辑
flow: context => {
return Promise.resolve("this is asyncTask1_child1");
}
},
{
name: "asyncTask1_child2", //异步逻辑
flow: context => {
return Promise.resolve(
"this is asyncTask1_child2" + context.asyncTask1_child1
);
}
}
]
};
const asyncTask2 = {
//flow 的名称
name: "asyncTask2",
//异步逻辑
flow: context => {
return Promise.resolve("asyncTask2" + context.asyncTask1);
},
children: {
asyncTask2_child1: {
name: "asyncTask2_child1", //异步逻辑
flow: context => {
return Promise.resolve("this is asyncTask2_child1");
}
},
asyncTask2_child2: {
name: "asyncTask2_child2", //异步逻辑
flow: context => {
return Promise.resolve(
"this is asyncTask2_child2" + context.asyncTask1_child1
);
}
}
}
};
//build async flow
const asyncFlow = buildFlow({}, { asyncTask1, asyncTask2 });
//运行 flowbb
asyncFlow.subscribe(context => {
console.log(context);
// {
// asyncTask1: "asyncTask1";
// asyncTask1_child1: "this is asyncTask1_child1";
// asyncTask1_child2: "this is asyncTask1_child2this is asyncTask1_child1";
// asyncTask2: "asyncTask2undefined";
// asyncTask2_child1: "this is asyncTask2_child1";
// asyncTask2_child2: "this is asyncTask2_child2undefined";
// }
});
flowConfig 里面的 flow 的返回值不仅仅可以是 promise,它还可以是其他 Observable. 由于 buildFlow 本身就会产生一个 Observable,所以可以嵌套使用. 嵌套使用的时候 context 不会被打平.
// 在线预览地址(将 index 文件替换为此文件): https://stackblitz.com/edit/ypzuhr-lkli1h?file=nest_flow.ts
import { buildFlow } from "@tomyail/async-flow";
const childFlowConfig = {
//flow 的名称
name: "childFlowConfig",
//异步逻辑
flow: context => {
return Promise.resolve(1);
}
};
const childFlow = buildFlow({}, [childFlowConfig]);
// basic usage
const parentFlowConfig1 = {
//flow 的名称
name: "parentFlowConfig1",
//异步逻辑
flow: context => {
return childFlow;
}
};
const parentFlowConfig2 = {
//flow 的名称
name: "parentFlowConfig2",
//异步逻辑
flow: context => {
return Promise.resolve(2);
}
};
const asyncFlow = buildFlow({}, [parentFlowConfig1, parentFlowConfig2]);
asyncFlow.subscribe(context => {
console.log(context);
// {
// parentFlowConfig1: {
// childFlowConfig: 1;
// }
// parentFlowConfig2: 2;
// }
});