/
AsyncGenerator.js
112 lines (99 loc) 路 3.07 KB
/
AsyncGenerator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/* @minVersion 7.0.0-beta.0 */
import OverloadYield from "OverloadYield";
export default function AsyncGenerator(gen) {
var front, back;
function send(key, arg) {
return new Promise(function (resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null,
};
if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}
function resume(key, arg) {
try {
var result = gen[key](arg);
var value = result.value;
var overloaded = value instanceof OverloadYield;
Promise.resolve(overloaded ? value.v : value).then(
function (arg) {
if (overloaded) {
// Overloaded yield requires calling into the generator twice:
// - first we get the iterator result wrapped in a promise
// (the gen[key](arg) call above)
// - then we await it (the Promise.resolve call above)
// - then we give the result back to the iterator, so that it can:
// * if it was an await, use its result
// * if it was a yield*, possibly return the `done: true` signal
// so that yield* knows that the iterator is finished.
// This needs to happen in the second call, because in the
// first one `done: true` was hidden in the promise and thus
// not visible to the (sync) yield*.
// The other part of this implementation is in asyncGeneratorDelegate.
var nextKey = key === "return" ? "return" : "next";
if (!value.k || arg.done) {
// await or end of yield*
return resume(nextKey, arg);
} else {
// yield*, not done
arg = gen[nextKey](arg).value;
}
}
settle(result.done ? "return" : "normal", arg);
},
function (err) {
resume("throw", err);
}
);
} catch (err) {
settle("throw", err);
}
}
function settle(type, value) {
switch (type) {
case "return":
front.resolve({ value: value, done: true });
break;
case "throw":
front.reject(value);
break;
default:
front.resolve({ value: value, done: false });
break;
}
front = front.next;
if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}
this._invoke = send;
// Hide "return" method if generator return is not supported
if (typeof gen.return !== "function") {
this.return = undefined;
}
}
AsyncGenerator.prototype[
(typeof Symbol === "function" && Symbol.asyncIterator) || "@@asyncIterator"
] = function () {
return this;
};
AsyncGenerator.prototype.next = function (arg) {
return this._invoke("next", arg);
};
AsyncGenerator.prototype.throw = function (arg) {
return this._invoke("throw", arg);
};
AsyncGenerator.prototype.return = function (arg) {
return this._invoke("return", arg);
};