@gaubee/flow
Version:
启发于 kotlin 的 flow,针对 js/ts 开发人员设计的接口,通常可以作为一个事件管理器
95 lines (94 loc) • 2.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.sharedFlow = exports.SharedFlow = void 0;
const util_1 = require("@gaubee/util");
/**
* 个极简的事件监听, 支持异步错误捕捉
* 对流有着极好的支持,支持背压,因此你甚至可以把它当作一个流发射器
*
* @example
* ```ts
* const flow = new SharedFlow<number>();
*
* const off = flow.on((data) => {
* console.log('on data', data)
* })
*
* async function once() {
* flow.once((data) => {
* console.log('once data', data)
* })
* console.log('await once data', await flow.once())
* }
*
* async function emit() {
* for (let i = 0; i < 10; i++) {
* await flow.emit(i);
* }
* }
*
* async function stream() {
* for await (const data of flow) {
* await delay(1000);
* console.log('for await', data);
* }
* }
* ```
*/
class SharedFlow extends util_1.PureEventDelegate {
constructor(by = new util_1.PureEvent()) {
super(by);
}
/**
* 将事件以流的方式发出
* 和使用 `for await (const data of flow)` 的方式来隐性触发流监听不同,这里的 stream 函数在调用的时候,就会立刻进行数据监听,因此可以避免一些执行顺序的误会
*/
stream(options) {
const readable = (0, util_1.rs_with_controller)();
const off = this.on(async (data) => {
readable.controller.enqueue(data);
if ((readable.controller.desiredSize ?? 1) <= 0) {
await readable.onPull.once();
}
}, {
...options,
onDispose() {
stream.return();
options?.onDispose?.();
},
});
// 在流结束的时候,清理监听
readable.onCancel.once(() => {
readable.onPull.clean();
off();
});
const stream = this.#stream(readable);
return stream;
}
async *#stream(readable) {
try {
const reader = readable.stream.getReader();
while (true) {
const item = await reader.read();
if (item.done) {
break;
}
yield item.value;
}
}
catch (e) {
console.log("catch", e);
readable.controller.error(e);
}
finally {
console.log("finally");
readable.controller.close();
}
}
[Symbol.asyncIterator]() {
return this.stream();
}
}
exports.SharedFlow = SharedFlow;
const sharedFlow = (by) => new SharedFlow(by);
exports.sharedFlow = sharedFlow;