63 lines
2.0 KiB
JavaScript
63 lines
2.0 KiB
JavaScript
// The drivers of async fns and generators
|
|
//
|
|
// The compiler lowers each async fn and generator to a coroutine (see
|
|
// compiler/src/transform/async.rs): a step closure, which runs the body until
|
|
// it suspends or returns, and an object `co`:
|
|
//
|
|
// { __proto__: <a proto below>, step, value, awaiting, result, done }
|
|
//
|
|
// A yield puts its value in `value`, an await puts its promise in `awaiting`,
|
|
// and a return puts its value in `result` and sets `done`. The fn returns
|
|
// `co.start()`. Only these drivers differ between the kinds
|
|
//
|
|
// Not supported yet: `throw()` on a generator, and `finally` blocks in
|
|
// `return()`, which need exceptions
|
|
|
|
// A generator's object is `co` itself
|
|
const __GeneratorProto = {
|
|
// The body runs up to its `initial_yield`, after its params
|
|
start() {
|
|
this.step(undefined);
|
|
return this;
|
|
},
|
|
|
|
next(input) {
|
|
if (this.done) return { value: undefined, done: true };
|
|
|
|
this.step(input);
|
|
|
|
if (this.done) return { value: this.result, done: true };
|
|
return { value: this.value, done: false };
|
|
},
|
|
|
|
return(value) {
|
|
this.done = true;
|
|
return { value: value, done: true };
|
|
},
|
|
};
|
|
|
|
// An async fn returns a promise, which its return fulfils. A rejected await
|
|
// rejects it, and the rest of the body does not run, as an uncaught throw at the
|
|
// await would
|
|
const __AsyncProto = {
|
|
// The body runs up to its first await, in the call
|
|
start() {
|
|
const promise = new Promise(undefined);
|
|
this.run(promise);
|
|
return promise;
|
|
},
|
|
|
|
run(promise) {
|
|
this.step(undefined);
|
|
|
|
if (this.done) __resolve(promise, this.result);
|
|
else this.awaiting.then(() => this.run(promise), (reason) => __reject(promise, reason));
|
|
},
|
|
|
|
// What an await waits on: a promise as it is, any other value as a fulfilled one.
|
|
// The step reads the value from it when it resumes
|
|
toPromise(x) {
|
|
return __is_promise(x) ? x : Promise.resolve(x);
|
|
},
|
|
};
|