You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					224 lines
				
				7.6 KiB
			
		
		
			
		
	
	
					224 lines
				
				7.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								module.exports = function(Promise,
							 | 
						||
| 
								 | 
							
								                          apiRejection,
							 | 
						||
| 
								 | 
							
								                          INTERNAL,
							 | 
						||
| 
								 | 
							
								                          tryConvertToPromise,
							 | 
						||
| 
								 | 
							
								                          Proxyable,
							 | 
						||
| 
								 | 
							
								                          debug) {
							 | 
						||
| 
								 | 
							
								var errors = require("./errors");
							 | 
						||
| 
								 | 
							
								var TypeError = errors.TypeError;
							 | 
						||
| 
								 | 
							
								var util = require("./util");
							 | 
						||
| 
								 | 
							
								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) {
							 | 
						||
| 
								 | 
							
								    if (debug.cancellation()) {
							 | 
						||
| 
								 | 
							
								        var internal = new Promise(INTERNAL);
							 | 
						||
| 
								 | 
							
								        var _finallyPromise = this._finallyPromise = new Promise(INTERNAL);
							 | 
						||
| 
								 | 
							
								        this._promise = internal.lastly(function() {
							 | 
						||
| 
								 | 
							
								            return _finallyPromise;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        internal._captureStackTrace();
							 | 
						||
| 
								 | 
							
								        internal._setOnCancel(this);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        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;
							 | 
						||
| 
								 | 
							
								    this._yieldedPromise = null;
							 | 
						||
| 
								 | 
							
								    this._cancellationPhase = false;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								util.inherits(PromiseSpawn, Proxyable);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._isResolved = function() {
							 | 
						||
| 
								 | 
							
								    return this._promise === null;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._cleanup = function() {
							 | 
						||
| 
								 | 
							
								    this._promise = this._generator = null;
							 | 
						||
| 
								 | 
							
								    if (debug.cancellation() && this._finallyPromise !== null) {
							 | 
						||
| 
								 | 
							
								        this._finallyPromise._fulfill();
							 | 
						||
| 
								 | 
							
								        this._finallyPromise = null;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._promiseCancelled = function() {
							 | 
						||
| 
								 | 
							
								    if (this._isResolved()) return;
							 | 
						||
| 
								 | 
							
								    var implementsReturn = typeof this._generator["return"] !== "undefined";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var result;
							 | 
						||
| 
								 | 
							
								    if (!implementsReturn) {
							 | 
						||
| 
								 | 
							
								        var reason = new Promise.CancellationError(
							 | 
						||
| 
								 | 
							
								            "generator .return() sentinel");
							 | 
						||
| 
								 | 
							
								        Promise.coroutine.returnSentinel = reason;
							 | 
						||
| 
								 | 
							
								        this._promise._attachExtraTrace(reason);
							 | 
						||
| 
								 | 
							
								        this._promise._pushContext();
							 | 
						||
| 
								 | 
							
								        result = tryCatch(this._generator["throw"]).call(this._generator,
							 | 
						||
| 
								 | 
							
								                                                         reason);
							 | 
						||
| 
								 | 
							
								        this._promise._popContext();
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        this._promise._pushContext();
							 | 
						||
| 
								 | 
							
								        result = tryCatch(this._generator["return"]).call(this._generator,
							 | 
						||
| 
								 | 
							
								                                                          undefined);
							 | 
						||
| 
								 | 
							
								        this._promise._popContext();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this._cancellationPhase = true;
							 | 
						||
| 
								 | 
							
								    this._yieldedPromise = null;
							 | 
						||
| 
								 | 
							
								    this._continue(result);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._promiseFulfilled = function(value) {
							 | 
						||
| 
								 | 
							
								    this._yieldedPromise = null;
							 | 
						||
| 
								 | 
							
								    this._promise._pushContext();
							 | 
						||
| 
								 | 
							
								    var result = tryCatch(this._generator.next).call(this._generator, value);
							 | 
						||
| 
								 | 
							
								    this._promise._popContext();
							 | 
						||
| 
								 | 
							
								    this._continue(result);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._promiseRejected = function(reason) {
							 | 
						||
| 
								 | 
							
								    this._yieldedPromise = null;
							 | 
						||
| 
								 | 
							
								    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._resultCancelled = function() {
							 | 
						||
| 
								 | 
							
								    if (this._yieldedPromise instanceof Promise) {
							 | 
						||
| 
								 | 
							
								        var promise = this._yieldedPromise;
							 | 
						||
| 
								 | 
							
								        this._yieldedPromise = null;
							 | 
						||
| 
								 | 
							
								        promise.cancel();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype.promise = function () {
							 | 
						||
| 
								 | 
							
								    return this._promise;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._run = function () {
							 | 
						||
| 
								 | 
							
								    this._generator = this._generatorFunction.call(this._receiver);
							 | 
						||
| 
								 | 
							
								    this._receiver =
							 | 
						||
| 
								 | 
							
								        this._generatorFunction = undefined;
							 | 
						||
| 
								 | 
							
								    this._promiseFulfilled(undefined);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PromiseSpawn.prototype._continue = function (result) {
							 | 
						||
| 
								 | 
							
								    var promise = this._promise;
							 | 
						||
| 
								 | 
							
								    if (result === errorObj) {
							 | 
						||
| 
								 | 
							
								        this._cleanup();
							 | 
						||
| 
								 | 
							
								        if (this._cancellationPhase) {
							 | 
						||
| 
								 | 
							
								            return promise.cancel();
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return promise._rejectCallback(result.e, false);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var value = result.value;
							 | 
						||
| 
								 | 
							
								    if (result.done === true) {
							 | 
						||
| 
								 | 
							
								        this._cleanup();
							 | 
						||
| 
								 | 
							
								        if (this._cancellationPhase) {
							 | 
						||
| 
								 | 
							
								            return promise.cancel();
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            return 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._promiseRejected(
							 | 
						||
| 
								 | 
							
								                    new TypeError(
							 | 
						||
| 
								 | 
							
								                        "A value %s was yielded that could not be treated as a promise\u000a\u000a    See http://goo.gl/MqrFmX\u000a\u000a".replace("%s", String(value)) +
							 | 
						||
| 
								 | 
							
								                        "From coroutine:\u000a" +
							 | 
						||
| 
								 | 
							
								                        this._stack.split("\n").slice(1, -7).join("\n")
							 | 
						||
| 
								 | 
							
								                    )
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        maybePromise = maybePromise._target();
							 | 
						||
| 
								 | 
							
								        var bitField = maybePromise._bitField;
							 | 
						||
| 
								 | 
							
								        ;
							 | 
						||
| 
								 | 
							
								        if (((bitField & 50397184) === 0)) {
							 | 
						||
| 
								 | 
							
								            this._yieldedPromise = maybePromise;
							 | 
						||
| 
								 | 
							
								            maybePromise._proxy(this, null);
							 | 
						||
| 
								 | 
							
								        } else if (((bitField & 33554432) !== 0)) {
							 | 
						||
| 
								 | 
							
								            Promise._async.invoke(
							 | 
						||
| 
								 | 
							
								                this._promiseFulfilled, this, maybePromise._value()
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        } else if (((bitField & 16777216) !== 0)) {
							 | 
						||
| 
								 | 
							
								            Promise._async.invoke(
							 | 
						||
| 
								 | 
							
								                this._promiseRejected, this, maybePromise._reason()
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            this._promiseCancelled();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Promise.coroutine = function (generatorFunction, options) {
							 | 
						||
| 
								 | 
							
								    if (typeof generatorFunction !== "function") {
							 | 
						||
| 
								 | 
							
								        throw new TypeError("generatorFunction must be a function\u000a\u000a    See http://goo.gl/MqrFmX\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);
							 | 
						||
| 
								 | 
							
								        var ret = spawn.promise();
							 | 
						||
| 
								 | 
							
								        spawn._generator = generator;
							 | 
						||
| 
								 | 
							
								        spawn._promiseFulfilled(undefined);
							 | 
						||
| 
								 | 
							
								        return ret;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Promise.coroutine.addYieldHandler = function(fn) {
							 | 
						||
| 
								 | 
							
								    if (typeof fn !== "function") {
							 | 
						||
| 
								 | 
							
								        throw new TypeError("expecting a function but got " + util.classString(fn));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    yieldHandlers.push(fn);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Promise.spawn = function (generatorFunction) {
							 | 
						||
| 
								 | 
							
								    debug.deprecated("Promise.spawn()", "Promise.coroutine()");
							 | 
						||
| 
								 | 
							
								    if (typeof generatorFunction !== "function") {
							 | 
						||
| 
								 | 
							
								        return apiRejection("generatorFunction must be a function\u000a\u000a    See http://goo.gl/MqrFmX\u000a");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    var spawn = new PromiseSpawn(generatorFunction, this);
							 | 
						||
| 
								 | 
							
								    var ret = spawn.promise();
							 | 
						||
| 
								 | 
							
								    spawn._run(Promise.spawn);
							 | 
						||
| 
								 | 
							
								    return ret;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								};
							 |