Skip to content

Instantly share code, notes, and snippets.

@ZeekoZhu
Created October 12, 2021 02:33
use async/await to build mst-flow but preserves action context
import { flow, onAction, types } from "mobx-state-tree";
type Work = (...args) => void | undefined;
class Workflow {
private queue = [];
private _resolve;
private resolved;
private _disposed = false;
get disposed() {
return this._disposed;
}
private release() {
if (this.resolved) {
this._resolve?.();
} else {
this.resolved = new Promise<unknown>(resolve => this._resolve = resolve);
this._resolve();
}
}
private async lock() {
// wait existing lock
if (this.resolved) {
await this.resolved;
}
// set new lock
this.resolved = new Promise<unknown>(resolve => this._resolve = resolve);
return this.resolved;
}
yield(work: Work) {
const result = new Promise(resolve => {
this.queue.push([work, resolve]);
});
this.release();
return result;
}
async run() {
await this.lock();
const task = this.queue.pop();
return () => {
if (task) {
const [work, resolve] = task;
work?.();
resolve?.();
}
}
}
dispose() {
this._disposed = true;
this.release();
}
}
type MstAction = (work: Work) => Promise<void>;
const asyncFlow = <TA extends any[], T>(workflow: (mstAction: MstAction) => (...args: TA) => Promise<T>) => {
const wf = new Workflow();
const mstAction: MstAction = async (work: Work) => {
await wf.yield(work);
};
return flow(function* (...args: TA) {
const result = Promise.resolve().then(() => workflow(mstAction)(...args).finally(() => {
wf.dispose();
}));
while (!wf.disposed) {
(yield wf.run())();
}
return yield result;
});
}
const foo = types.model('Foo', {
foo: ''
}).actions(self => {
return {
asyncOp: asyncFlow(mstAction => async (bar: string) => {
await mstAction(() => self.foo = '123')
console.log('foo: ' + self.foo);
await mstAction(() => self.foo = self.foo + '123')
return 3;
})
}
});
(async () => {
try {
let tree = foo.create();
onAction(tree, c => console.log(c.name, c.path));
await tree.asyncOp('foo').then((x) => console.log('finished ' + x))
} catch (e) {
console.log(e)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment