Implement support for async generator functions and for-await statements
This commit is contained in:
@@ -61,6 +61,158 @@ helpers.jsx = template(`
|
||||
})()
|
||||
`);
|
||||
|
||||
helpers.asyncIterator = template(`
|
||||
(function (iterable) {
|
||||
if (typeof Symbol === "function") {
|
||||
if (Symbol.asyncIterator) {
|
||||
var method = iterable[Symbol.asyncIterator];
|
||||
if (method != null) return method.call(iterable);
|
||||
}
|
||||
if (Symbol.iterator) {
|
||||
return iterable[Symbol.iterator]();
|
||||
}
|
||||
}
|
||||
throw new TypeError("Object is not async iterable");
|
||||
})
|
||||
`);
|
||||
|
||||
helpers.asyncGenerator = template(`
|
||||
(function () {
|
||||
function AwaitValue(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
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;
|
||||
if (value instanceof AwaitValue) {
|
||||
Promise.resolve(value.value).then(
|
||||
function (arg) { resume("next", arg); },
|
||||
function (arg) { resume("throw", arg); });
|
||||
} else {
|
||||
settle(result.done ? "return" : "normal", result.value);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof Symbol === "function" && Symbol.asyncIterator) {
|
||||
AsyncGenerator.prototype[Symbol.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); };
|
||||
|
||||
return {
|
||||
wrap: function (fn) {
|
||||
return function () {
|
||||
return new AsyncGenerator(fn.apply(this, arguments));
|
||||
};
|
||||
},
|
||||
await: function (value) {
|
||||
return new AwaitValue(value);
|
||||
}
|
||||
};
|
||||
|
||||
})()
|
||||
`);
|
||||
|
||||
helpers.asyncGeneratorDelegate = template(`
|
||||
(function (inner, awaitWrap) {
|
||||
var iter = {}, waiting = false;
|
||||
|
||||
function pump(key, value) {
|
||||
waiting = true;
|
||||
value = new Promise(function (resolve) { resolve(inner[key](value)); });
|
||||
return { done: false, value: awaitWrap(value) };
|
||||
};
|
||||
|
||||
if (typeof Symbol === "function" && Symbol.iterator) {
|
||||
iter[Symbol.iterator] = function () { return this; };
|
||||
}
|
||||
|
||||
iter.next = function (value) {
|
||||
if (waiting) {
|
||||
waiting = false;
|
||||
return value;
|
||||
}
|
||||
return pump("next", value);
|
||||
};
|
||||
|
||||
if (typeof inner.throw === "function") {
|
||||
iter.throw = function (value) {
|
||||
if (waiting) {
|
||||
waiting = false;
|
||||
throw value;
|
||||
}
|
||||
return pump("throw", value);
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof inner.return === "function") {
|
||||
iter.return = function (value) {
|
||||
return pump("return", value);
|
||||
};
|
||||
}
|
||||
|
||||
return iter;
|
||||
})
|
||||
`);
|
||||
|
||||
helpers.asyncToGenerator = template(`
|
||||
(function (fn) {
|
||||
return function () {
|
||||
@@ -92,7 +244,6 @@ helpers.asyncToGenerator = template(`
|
||||
})
|
||||
`);
|
||||
|
||||
|
||||
helpers.classCallCheck = template(`
|
||||
(function (instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
|
||||
Reference in New Issue
Block a user