137 lines
4.6 KiB
JavaScript
137 lines
4.6 KiB
JavaScript
|
"use strict";
|
||
|
module.exports = function(Promise,
|
||
|
apiRejection,
|
||
|
INTERNAL,
|
||
|
tryConvertToPromise) {
|
||
|
var errors = require("./errors.js");
|
||
|
var TypeError = errors.TypeError;
|
||
|
var util = require("./util.js");
|
||
|
var errorObj = util.errorObj;
|
||
|
var tryCatch = util.tryCatch;
|
||
|
var yieldHandlers = [];
|
||
|
|
||
|
function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
|
||
|
for (var i = 0; i < yieldHandlers.length; ++i) {
|
||
|
traceParent._pushContext();
|
||
|
var result = tryCatch(yieldHandlers[i])(value);
|
||
|
traceParent._popContext();
|
||
|
if (result === errorObj) {
|
||
|
traceParent._pushContext();
|
||
|
var ret = Promise.reject(errorObj.e);
|
||
|
traceParent._popContext();
|
||
|
return ret;
|
||
|
}
|
||
|
var maybePromise = tryConvertToPromise(result, traceParent);
|
||
|
if (maybePromise instanceof Promise) return maybePromise;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
|
||
|
var promise = this._promise = new Promise(INTERNAL);
|
||
|
promise._captureStackTrace();
|
||
|
this._stack = stack;
|
||
|
this._generatorFunction = generatorFunction;
|
||
|
this._receiver = receiver;
|
||
|
this._generator = undefined;
|
||
|
this._yieldHandlers = typeof yieldHandler === "function"
|
||
|
? [yieldHandler].concat(yieldHandlers)
|
||
|
: yieldHandlers;
|
||
|
}
|
||
|
|
||
|
PromiseSpawn.prototype.promise = function () {
|
||
|
return this._promise;
|
||
|
};
|
||
|
|
||
|
PromiseSpawn.prototype._run = function () {
|
||
|
this._generator = this._generatorFunction.call(this._receiver);
|
||
|
this._receiver =
|
||
|
this._generatorFunction = undefined;
|
||
|
this._next(undefined);
|
||
|
};
|
||
|
|
||
|
PromiseSpawn.prototype._continue = function (result) {
|
||
|
if (result === errorObj) {
|
||
|
return this._promise._rejectCallback(result.e, false, true);
|
||
|
}
|
||
|
|
||
|
var value = result.value;
|
||
|
if (result.done === true) {
|
||
|
this._promise._resolveCallback(value);
|
||
|
} else {
|
||
|
var maybePromise = tryConvertToPromise(value, this._promise);
|
||
|
if (!(maybePromise instanceof Promise)) {
|
||
|
maybePromise =
|
||
|
promiseFromYieldHandler(maybePromise,
|
||
|
this._yieldHandlers,
|
||
|
this._promise);
|
||
|
if (maybePromise === null) {
|
||
|
this._throw(
|
||
|
new TypeError(
|
||
|
"A value %s was yielded that could not be treated as a promise\u000a\u000a See http://goo.gl/4Y4pDk\u000a\u000a".replace("%s", value) +
|
||
|
"From coroutine:\u000a" +
|
||
|
this._stack.split("\n").slice(1, -7).join("\n")
|
||
|
)
|
||
|
);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
maybePromise._then(
|
||
|
this._next,
|
||
|
this._throw,
|
||
|
undefined,
|
||
|
this,
|
||
|
null
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
PromiseSpawn.prototype._throw = function (reason) {
|
||
|
this._promise._attachExtraTrace(reason);
|
||
|
this._promise._pushContext();
|
||
|
var result = tryCatch(this._generator["throw"])
|
||
|
.call(this._generator, reason);
|
||
|
this._promise._popContext();
|
||
|
this._continue(result);
|
||
|
};
|
||
|
|
||
|
PromiseSpawn.prototype._next = function (value) {
|
||
|
this._promise._pushContext();
|
||
|
var result = tryCatch(this._generator.next).call(this._generator, value);
|
||
|
this._promise._popContext();
|
||
|
this._continue(result);
|
||
|
};
|
||
|
|
||
|
Promise.coroutine = function (generatorFunction, options) {
|
||
|
if (typeof generatorFunction !== "function") {
|
||
|
throw new TypeError("generatorFunction must be a function\u000a\u000a See http://goo.gl/6Vqhm0\u000a");
|
||
|
}
|
||
|
var yieldHandler = Object(options).yieldHandler;
|
||
|
var PromiseSpawn$ = PromiseSpawn;
|
||
|
var stack = new Error().stack;
|
||
|
return function () {
|
||
|
var generator = generatorFunction.apply(this, arguments);
|
||
|
var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
|
||
|
stack);
|
||
|
spawn._generator = generator;
|
||
|
spawn._next(undefined);
|
||
|
return spawn.promise();
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Promise.coroutine.addYieldHandler = function(fn) {
|
||
|
if (typeof fn !== "function") throw new TypeError("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
|
||
|
yieldHandlers.push(fn);
|
||
|
};
|
||
|
|
||
|
Promise.spawn = function (generatorFunction) {
|
||
|
if (typeof generatorFunction !== "function") {
|
||
|
return apiRejection("generatorFunction must be a function\u000a\u000a See http://goo.gl/6Vqhm0\u000a");
|
||
|
}
|
||
|
var spawn = new PromiseSpawn(generatorFunction, this);
|
||
|
var ret = spawn.promise();
|
||
|
spawn._run(Promise.spawn);
|
||
|
return ret;
|
||
|
};
|
||
|
};
|