82f2b76e25
We now use webpack instead of SystemJS, effectively bundling modules into one file (plus commons chunks) for every entry point. This results in a much smaller extension size (almost half). Furthermore we use yarn/npm even for extension run-time dependencies. This relieves us from manually vendoring and building dependencies. It's also easier to understand for new developers familiar with node.
956 lines
23 KiB
JavaScript
956 lines
23 KiB
JavaScript
/** @license MIT License (c) copyright 2010-2014 original author or authors */
|
|
/** @author Brian Cavalier */
|
|
/** @author John Hann */
|
|
|
|
(function(define) { 'use strict';
|
|
define(function() {
|
|
|
|
return function makePromise(environment) {
|
|
|
|
var tasks = environment.scheduler;
|
|
var emitRejection = initEmitRejection();
|
|
|
|
var objectCreate = Object.create ||
|
|
function(proto) {
|
|
function Child() {}
|
|
Child.prototype = proto;
|
|
return new Child();
|
|
};
|
|
|
|
/**
|
|
* Create a promise whose fate is determined by resolver
|
|
* @constructor
|
|
* @returns {Promise} promise
|
|
* @name Promise
|
|
*/
|
|
function Promise(resolver, handler) {
|
|
this._handler = resolver === Handler ? handler : init(resolver);
|
|
}
|
|
|
|
/**
|
|
* Run the supplied resolver
|
|
* @param resolver
|
|
* @returns {Pending}
|
|
*/
|
|
function init(resolver) {
|
|
var handler = new Pending();
|
|
|
|
try {
|
|
resolver(promiseResolve, promiseReject, promiseNotify);
|
|
} catch (e) {
|
|
promiseReject(e);
|
|
}
|
|
|
|
return handler;
|
|
|
|
/**
|
|
* Transition from pre-resolution state to post-resolution state, notifying
|
|
* all listeners of the ultimate fulfillment or rejection
|
|
* @param {*} x resolution value
|
|
*/
|
|
function promiseResolve (x) {
|
|
handler.resolve(x);
|
|
}
|
|
/**
|
|
* Reject this promise with reason, which will be used verbatim
|
|
* @param {Error|*} reason rejection reason, strongly suggested
|
|
* to be an Error type
|
|
*/
|
|
function promiseReject (reason) {
|
|
handler.reject(reason);
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* Issue a progress event, notifying all progress listeners
|
|
* @param {*} x progress event payload to pass to all listeners
|
|
*/
|
|
function promiseNotify (x) {
|
|
handler.notify(x);
|
|
}
|
|
}
|
|
|
|
// Creation
|
|
|
|
Promise.resolve = resolve;
|
|
Promise.reject = reject;
|
|
Promise.never = never;
|
|
|
|
Promise._defer = defer;
|
|
Promise._handler = getHandler;
|
|
|
|
/**
|
|
* Returns a trusted promise. If x is already a trusted promise, it is
|
|
* returned, otherwise returns a new trusted Promise which follows x.
|
|
* @param {*} x
|
|
* @return {Promise} promise
|
|
*/
|
|
function resolve(x) {
|
|
return isPromise(x) ? x
|
|
: new Promise(Handler, new Async(getHandler(x)));
|
|
}
|
|
|
|
/**
|
|
* Return a reject promise with x as its reason (x is used verbatim)
|
|
* @param {*} x
|
|
* @returns {Promise} rejected promise
|
|
*/
|
|
function reject(x) {
|
|
return new Promise(Handler, new Async(new Rejected(x)));
|
|
}
|
|
|
|
/**
|
|
* Return a promise that remains pending forever
|
|
* @returns {Promise} forever-pending promise.
|
|
*/
|
|
function never() {
|
|
return foreverPendingPromise; // Should be frozen
|
|
}
|
|
|
|
/**
|
|
* Creates an internal {promise, resolver} pair
|
|
* @private
|
|
* @returns {Promise}
|
|
*/
|
|
function defer() {
|
|
return new Promise(Handler, new Pending());
|
|
}
|
|
|
|
// Transformation and flow control
|
|
|
|
/**
|
|
* Transform this promise's fulfillment value, returning a new Promise
|
|
* for the transformed result. If the promise cannot be fulfilled, onRejected
|
|
* is called with the reason. onProgress *may* be called with updates toward
|
|
* this promise's fulfillment.
|
|
* @param {function=} onFulfilled fulfillment handler
|
|
* @param {function=} onRejected rejection handler
|
|
* @param {function=} onProgress @deprecated progress handler
|
|
* @return {Promise} new promise
|
|
*/
|
|
Promise.prototype.then = function(onFulfilled, onRejected, onProgress) {
|
|
var parent = this._handler;
|
|
var state = parent.join().state();
|
|
|
|
if ((typeof onFulfilled !== 'function' && state > 0) ||
|
|
(typeof onRejected !== 'function' && state < 0)) {
|
|
// Short circuit: value will not change, simply share handler
|
|
return new this.constructor(Handler, parent);
|
|
}
|
|
|
|
var p = this._beget();
|
|
var child = p._handler;
|
|
|
|
parent.chain(child, parent.receiver, onFulfilled, onRejected, onProgress);
|
|
|
|
return p;
|
|
};
|
|
|
|
/**
|
|
* If this promise cannot be fulfilled due to an error, call onRejected to
|
|
* handle the error. Shortcut for .then(undefined, onRejected)
|
|
* @param {function?} onRejected
|
|
* @return {Promise}
|
|
*/
|
|
Promise.prototype['catch'] = function(onRejected) {
|
|
return this.then(void 0, onRejected);
|
|
};
|
|
|
|
/**
|
|
* Creates a new, pending promise of the same type as this promise
|
|
* @private
|
|
* @returns {Promise}
|
|
*/
|
|
Promise.prototype._beget = function() {
|
|
return begetFrom(this._handler, this.constructor);
|
|
};
|
|
|
|
function begetFrom(parent, Promise) {
|
|
var child = new Pending(parent.receiver, parent.join().context);
|
|
return new Promise(Handler, child);
|
|
}
|
|
|
|
// Array combinators
|
|
|
|
Promise.all = all;
|
|
Promise.race = race;
|
|
Promise._traverse = traverse;
|
|
|
|
/**
|
|
* Return a promise that will fulfill when all promises in the
|
|
* input array have fulfilled, or will reject when one of the
|
|
* promises rejects.
|
|
* @param {array} promises array of promises
|
|
* @returns {Promise} promise for array of fulfillment values
|
|
*/
|
|
function all(promises) {
|
|
return traverseWith(snd, null, promises);
|
|
}
|
|
|
|
/**
|
|
* Array<Promise<X>> -> Promise<Array<f(X)>>
|
|
* @private
|
|
* @param {function} f function to apply to each promise's value
|
|
* @param {Array} promises array of promises
|
|
* @returns {Promise} promise for transformed values
|
|
*/
|
|
function traverse(f, promises) {
|
|
return traverseWith(tryCatch2, f, promises);
|
|
}
|
|
|
|
function traverseWith(tryMap, f, promises) {
|
|
var handler = typeof f === 'function' ? mapAt : settleAt;
|
|
|
|
var resolver = new Pending();
|
|
var pending = promises.length >>> 0;
|
|
var results = new Array(pending);
|
|
|
|
for (var i = 0, x; i < promises.length && !resolver.resolved; ++i) {
|
|
x = promises[i];
|
|
|
|
if (x === void 0 && !(i in promises)) {
|
|
--pending;
|
|
continue;
|
|
}
|
|
|
|
traverseAt(promises, handler, i, x, resolver);
|
|
}
|
|
|
|
if(pending === 0) {
|
|
resolver.become(new Fulfilled(results));
|
|
}
|
|
|
|
return new Promise(Handler, resolver);
|
|
|
|
function mapAt(i, x, resolver) {
|
|
if(!resolver.resolved) {
|
|
traverseAt(promises, settleAt, i, tryMap(f, x, i), resolver);
|
|
}
|
|
}
|
|
|
|
function settleAt(i, x, resolver) {
|
|
results[i] = x;
|
|
if(--pending === 0) {
|
|
resolver.become(new Fulfilled(results));
|
|
}
|
|
}
|
|
}
|
|
|
|
function traverseAt(promises, handler, i, x, resolver) {
|
|
if (maybeThenable(x)) {
|
|
var h = getHandlerMaybeThenable(x);
|
|
var s = h.state();
|
|
|
|
if (s === 0) {
|
|
h.fold(handler, i, void 0, resolver);
|
|
} else if (s > 0) {
|
|
handler(i, h.value, resolver);
|
|
} else {
|
|
resolver.become(h);
|
|
visitRemaining(promises, i+1, h);
|
|
}
|
|
} else {
|
|
handler(i, x, resolver);
|
|
}
|
|
}
|
|
|
|
Promise._visitRemaining = visitRemaining;
|
|
function visitRemaining(promises, start, handler) {
|
|
for(var i=start; i<promises.length; ++i) {
|
|
markAsHandled(getHandler(promises[i]), handler);
|
|
}
|
|
}
|
|
|
|
function markAsHandled(h, handler) {
|
|
if(h === handler) {
|
|
return;
|
|
}
|
|
|
|
var s = h.state();
|
|
if(s === 0) {
|
|
h.visit(h, void 0, h._unreport);
|
|
} else if(s < 0) {
|
|
h._unreport();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fulfill-reject competitive race. Return a promise that will settle
|
|
* to the same state as the earliest input promise to settle.
|
|
*
|
|
* WARNING: The ES6 Promise spec requires that race()ing an empty array
|
|
* must return a promise that is pending forever. This implementation
|
|
* returns a singleton forever-pending promise, the same singleton that is
|
|
* returned by Promise.never(), thus can be checked with ===
|
|
*
|
|
* @param {array} promises array of promises to race
|
|
* @returns {Promise} if input is non-empty, a promise that will settle
|
|
* to the same outcome as the earliest input promise to settle. if empty
|
|
* is empty, returns a promise that will never settle.
|
|
*/
|
|
function race(promises) {
|
|
if(typeof promises !== 'object' || promises === null) {
|
|
return reject(new TypeError('non-iterable passed to race()'));
|
|
}
|
|
|
|
// Sigh, race([]) is untestable unless we return *something*
|
|
// that is recognizable without calling .then() on it.
|
|
return promises.length === 0 ? never()
|
|
: promises.length === 1 ? resolve(promises[0])
|
|
: runRace(promises);
|
|
}
|
|
|
|
function runRace(promises) {
|
|
var resolver = new Pending();
|
|
var i, x, h;
|
|
for(i=0; i<promises.length; ++i) {
|
|
x = promises[i];
|
|
if (x === void 0 && !(i in promises)) {
|
|
continue;
|
|
}
|
|
|
|
h = getHandler(x);
|
|
if(h.state() !== 0) {
|
|
resolver.become(h);
|
|
visitRemaining(promises, i+1, h);
|
|
break;
|
|
} else {
|
|
h.visit(resolver, resolver.resolve, resolver.reject);
|
|
}
|
|
}
|
|
return new Promise(Handler, resolver);
|
|
}
|
|
|
|
// Promise internals
|
|
// Below this, everything is @private
|
|
|
|
/**
|
|
* Get an appropriate handler for x, without checking for cycles
|
|
* @param {*} x
|
|
* @returns {object} handler
|
|
*/
|
|
function getHandler(x) {
|
|
if(isPromise(x)) {
|
|
return x._handler.join();
|
|
}
|
|
return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
|
|
}
|
|
|
|
/**
|
|
* Get a handler for thenable x.
|
|
* NOTE: You must only call this if maybeThenable(x) == true
|
|
* @param {object|function|Promise} x
|
|
* @returns {object} handler
|
|
*/
|
|
function getHandlerMaybeThenable(x) {
|
|
return isPromise(x) ? x._handler.join() : getHandlerUntrusted(x);
|
|
}
|
|
|
|
/**
|
|
* Get a handler for potentially untrusted thenable x
|
|
* @param {*} x
|
|
* @returns {object} handler
|
|
*/
|
|
function getHandlerUntrusted(x) {
|
|
try {
|
|
var untrustedThen = x.then;
|
|
return typeof untrustedThen === 'function'
|
|
? new Thenable(untrustedThen, x)
|
|
: new Fulfilled(x);
|
|
} catch(e) {
|
|
return new Rejected(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handler for a promise that is pending forever
|
|
* @constructor
|
|
*/
|
|
function Handler() {}
|
|
|
|
Handler.prototype.when
|
|
= Handler.prototype.become
|
|
= Handler.prototype.notify // deprecated
|
|
= Handler.prototype.fail
|
|
= Handler.prototype._unreport
|
|
= Handler.prototype._report
|
|
= noop;
|
|
|
|
Handler.prototype._state = 0;
|
|
|
|
Handler.prototype.state = function() {
|
|
return this._state;
|
|
};
|
|
|
|
/**
|
|
* Recursively collapse handler chain to find the handler
|
|
* nearest to the fully resolved value.
|
|
* @returns {object} handler nearest the fully resolved value
|
|
*/
|
|
Handler.prototype.join = function() {
|
|
var h = this;
|
|
while(h.handler !== void 0) {
|
|
h = h.handler;
|
|
}
|
|
return h;
|
|
};
|
|
|
|
Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
|
|
this.when({
|
|
resolver: to,
|
|
receiver: receiver,
|
|
fulfilled: fulfilled,
|
|
rejected: rejected,
|
|
progress: progress
|
|
});
|
|
};
|
|
|
|
Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
|
|
this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
|
|
};
|
|
|
|
Handler.prototype.fold = function(f, z, c, to) {
|
|
this.when(new Fold(f, z, c, to));
|
|
};
|
|
|
|
/**
|
|
* Handler that invokes fail() on any handler it becomes
|
|
* @constructor
|
|
*/
|
|
function FailIfRejected() {}
|
|
|
|
inherit(Handler, FailIfRejected);
|
|
|
|
FailIfRejected.prototype.become = function(h) {
|
|
h.fail();
|
|
};
|
|
|
|
var failIfRejected = new FailIfRejected();
|
|
|
|
/**
|
|
* Handler that manages a queue of consumers waiting on a pending promise
|
|
* @constructor
|
|
*/
|
|
function Pending(receiver, inheritedContext) {
|
|
Promise.createContext(this, inheritedContext);
|
|
|
|
this.consumers = void 0;
|
|
this.receiver = receiver;
|
|
this.handler = void 0;
|
|
this.resolved = false;
|
|
}
|
|
|
|
inherit(Handler, Pending);
|
|
|
|
Pending.prototype._state = 0;
|
|
|
|
Pending.prototype.resolve = function(x) {
|
|
this.become(getHandler(x));
|
|
};
|
|
|
|
Pending.prototype.reject = function(x) {
|
|
if(this.resolved) {
|
|
return;
|
|
}
|
|
|
|
this.become(new Rejected(x));
|
|
};
|
|
|
|
Pending.prototype.join = function() {
|
|
if (!this.resolved) {
|
|
return this;
|
|
}
|
|
|
|
var h = this;
|
|
|
|
while (h.handler !== void 0) {
|
|
h = h.handler;
|
|
if (h === this) {
|
|
return this.handler = cycle();
|
|
}
|
|
}
|
|
|
|
return h;
|
|
};
|
|
|
|
Pending.prototype.run = function() {
|
|
var q = this.consumers;
|
|
var handler = this.handler;
|
|
this.handler = this.handler.join();
|
|
this.consumers = void 0;
|
|
|
|
for (var i = 0; i < q.length; ++i) {
|
|
handler.when(q[i]);
|
|
}
|
|
};
|
|
|
|
Pending.prototype.become = function(handler) {
|
|
if(this.resolved) {
|
|
return;
|
|
}
|
|
|
|
this.resolved = true;
|
|
this.handler = handler;
|
|
if(this.consumers !== void 0) {
|
|
tasks.enqueue(this);
|
|
}
|
|
|
|
if(this.context !== void 0) {
|
|
handler._report(this.context);
|
|
}
|
|
};
|
|
|
|
Pending.prototype.when = function(continuation) {
|
|
if(this.resolved) {
|
|
tasks.enqueue(new ContinuationTask(continuation, this.handler));
|
|
} else {
|
|
if(this.consumers === void 0) {
|
|
this.consumers = [continuation];
|
|
} else {
|
|
this.consumers.push(continuation);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
Pending.prototype.notify = function(x) {
|
|
if(!this.resolved) {
|
|
tasks.enqueue(new ProgressTask(x, this));
|
|
}
|
|
};
|
|
|
|
Pending.prototype.fail = function(context) {
|
|
var c = typeof context === 'undefined' ? this.context : context;
|
|
this.resolved && this.handler.join().fail(c);
|
|
};
|
|
|
|
Pending.prototype._report = function(context) {
|
|
this.resolved && this.handler.join()._report(context);
|
|
};
|
|
|
|
Pending.prototype._unreport = function() {
|
|
this.resolved && this.handler.join()._unreport();
|
|
};
|
|
|
|
/**
|
|
* Wrap another handler and force it into a future stack
|
|
* @param {object} handler
|
|
* @constructor
|
|
*/
|
|
function Async(handler) {
|
|
this.handler = handler;
|
|
}
|
|
|
|
inherit(Handler, Async);
|
|
|
|
Async.prototype.when = function(continuation) {
|
|
tasks.enqueue(new ContinuationTask(continuation, this));
|
|
};
|
|
|
|
Async.prototype._report = function(context) {
|
|
this.join()._report(context);
|
|
};
|
|
|
|
Async.prototype._unreport = function() {
|
|
this.join()._unreport();
|
|
};
|
|
|
|
/**
|
|
* Handler that wraps an untrusted thenable and assimilates it in a future stack
|
|
* @param {function} then
|
|
* @param {{then: function}} thenable
|
|
* @constructor
|
|
*/
|
|
function Thenable(then, thenable) {
|
|
Pending.call(this);
|
|
tasks.enqueue(new AssimilateTask(then, thenable, this));
|
|
}
|
|
|
|
inherit(Pending, Thenable);
|
|
|
|
/**
|
|
* Handler for a fulfilled promise
|
|
* @param {*} x fulfillment value
|
|
* @constructor
|
|
*/
|
|
function Fulfilled(x) {
|
|
Promise.createContext(this);
|
|
this.value = x;
|
|
}
|
|
|
|
inherit(Handler, Fulfilled);
|
|
|
|
Fulfilled.prototype._state = 1;
|
|
|
|
Fulfilled.prototype.fold = function(f, z, c, to) {
|
|
runContinuation3(f, z, this, c, to);
|
|
};
|
|
|
|
Fulfilled.prototype.when = function(cont) {
|
|
runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
|
|
};
|
|
|
|
var errorId = 0;
|
|
|
|
/**
|
|
* Handler for a rejected promise
|
|
* @param {*} x rejection reason
|
|
* @constructor
|
|
*/
|
|
function Rejected(x) {
|
|
Promise.createContext(this);
|
|
|
|
this.id = ++errorId;
|
|
this.value = x;
|
|
this.handled = false;
|
|
this.reported = false;
|
|
|
|
this._report();
|
|
}
|
|
|
|
inherit(Handler, Rejected);
|
|
|
|
Rejected.prototype._state = -1;
|
|
|
|
Rejected.prototype.fold = function(f, z, c, to) {
|
|
to.become(this);
|
|
};
|
|
|
|
Rejected.prototype.when = function(cont) {
|
|
if(typeof cont.rejected === 'function') {
|
|
this._unreport();
|
|
}
|
|
runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
|
|
};
|
|
|
|
Rejected.prototype._report = function(context) {
|
|
tasks.afterQueue(new ReportTask(this, context));
|
|
};
|
|
|
|
Rejected.prototype._unreport = function() {
|
|
if(this.handled) {
|
|
return;
|
|
}
|
|
this.handled = true;
|
|
tasks.afterQueue(new UnreportTask(this));
|
|
};
|
|
|
|
Rejected.prototype.fail = function(context) {
|
|
this.reported = true;
|
|
emitRejection('unhandledRejection', this);
|
|
Promise.onFatalRejection(this, context === void 0 ? this.context : context);
|
|
};
|
|
|
|
function ReportTask(rejection, context) {
|
|
this.rejection = rejection;
|
|
this.context = context;
|
|
}
|
|
|
|
ReportTask.prototype.run = function() {
|
|
if(!this.rejection.handled && !this.rejection.reported) {
|
|
this.rejection.reported = true;
|
|
emitRejection('unhandledRejection', this.rejection) ||
|
|
Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
|
|
}
|
|
};
|
|
|
|
function UnreportTask(rejection) {
|
|
this.rejection = rejection;
|
|
}
|
|
|
|
UnreportTask.prototype.run = function() {
|
|
if(this.rejection.reported) {
|
|
emitRejection('rejectionHandled', this.rejection) ||
|
|
Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
|
|
}
|
|
};
|
|
|
|
// Unhandled rejection hooks
|
|
// By default, everything is a noop
|
|
|
|
Promise.createContext
|
|
= Promise.enterContext
|
|
= Promise.exitContext
|
|
= Promise.onPotentiallyUnhandledRejection
|
|
= Promise.onPotentiallyUnhandledRejectionHandled
|
|
= Promise.onFatalRejection
|
|
= noop;
|
|
|
|
// Errors and singletons
|
|
|
|
var foreverPendingHandler = new Handler();
|
|
var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
|
|
|
|
function cycle() {
|
|
return new Rejected(new TypeError('Promise cycle'));
|
|
}
|
|
|
|
// Task runners
|
|
|
|
/**
|
|
* Run a single consumer
|
|
* @constructor
|
|
*/
|
|
function ContinuationTask(continuation, handler) {
|
|
this.continuation = continuation;
|
|
this.handler = handler;
|
|
}
|
|
|
|
ContinuationTask.prototype.run = function() {
|
|
this.handler.join().when(this.continuation);
|
|
};
|
|
|
|
/**
|
|
* Run a queue of progress handlers
|
|
* @constructor
|
|
*/
|
|
function ProgressTask(value, handler) {
|
|
this.handler = handler;
|
|
this.value = value;
|
|
}
|
|
|
|
ProgressTask.prototype.run = function() {
|
|
var q = this.handler.consumers;
|
|
if(q === void 0) {
|
|
return;
|
|
}
|
|
|
|
for (var c, i = 0; i < q.length; ++i) {
|
|
c = q[i];
|
|
runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Assimilate a thenable, sending it's value to resolver
|
|
* @param {function} then
|
|
* @param {object|function} thenable
|
|
* @param {object} resolver
|
|
* @constructor
|
|
*/
|
|
function AssimilateTask(then, thenable, resolver) {
|
|
this._then = then;
|
|
this.thenable = thenable;
|
|
this.resolver = resolver;
|
|
}
|
|
|
|
AssimilateTask.prototype.run = function() {
|
|
var h = this.resolver;
|
|
tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
|
|
|
|
function _resolve(x) { h.resolve(x); }
|
|
function _reject(x) { h.reject(x); }
|
|
function _notify(x) { h.notify(x); }
|
|
};
|
|
|
|
function tryAssimilate(then, thenable, resolve, reject, notify) {
|
|
try {
|
|
then.call(thenable, resolve, reject, notify);
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fold a handler value with z
|
|
* @constructor
|
|
*/
|
|
function Fold(f, z, c, to) {
|
|
this.f = f; this.z = z; this.c = c; this.to = to;
|
|
this.resolver = failIfRejected;
|
|
this.receiver = this;
|
|
}
|
|
|
|
Fold.prototype.fulfilled = function(x) {
|
|
this.f.call(this.c, this.z, x, this.to);
|
|
};
|
|
|
|
Fold.prototype.rejected = function(x) {
|
|
this.to.reject(x);
|
|
};
|
|
|
|
Fold.prototype.progress = function(x) {
|
|
this.to.notify(x);
|
|
};
|
|
|
|
// Other helpers
|
|
|
|
/**
|
|
* @param {*} x
|
|
* @returns {boolean} true iff x is a trusted Promise
|
|
*/
|
|
function isPromise(x) {
|
|
return x instanceof Promise;
|
|
}
|
|
|
|
/**
|
|
* Test just enough to rule out primitives, in order to take faster
|
|
* paths in some code
|
|
* @param {*} x
|
|
* @returns {boolean} false iff x is guaranteed *not* to be a thenable
|
|
*/
|
|
function maybeThenable(x) {
|
|
return (typeof x === 'object' || typeof x === 'function') && x !== null;
|
|
}
|
|
|
|
function runContinuation1(f, h, receiver, next) {
|
|
if(typeof f !== 'function') {
|
|
return next.become(h);
|
|
}
|
|
|
|
Promise.enterContext(h);
|
|
tryCatchReject(f, h.value, receiver, next);
|
|
Promise.exitContext();
|
|
}
|
|
|
|
function runContinuation3(f, x, h, receiver, next) {
|
|
if(typeof f !== 'function') {
|
|
return next.become(h);
|
|
}
|
|
|
|
Promise.enterContext(h);
|
|
tryCatchReject3(f, x, h.value, receiver, next);
|
|
Promise.exitContext();
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
function runNotify(f, x, h, receiver, next) {
|
|
if(typeof f !== 'function') {
|
|
return next.notify(x);
|
|
}
|
|
|
|
Promise.enterContext(h);
|
|
tryCatchReturn(f, x, receiver, next);
|
|
Promise.exitContext();
|
|
}
|
|
|
|
function tryCatch2(f, a, b) {
|
|
try {
|
|
return f(a, b);
|
|
} catch(e) {
|
|
return reject(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return f.call(thisArg, x), or if it throws return a rejected promise for
|
|
* the thrown exception
|
|
*/
|
|
function tryCatchReject(f, x, thisArg, next) {
|
|
try {
|
|
next.become(getHandler(f.call(thisArg, x)));
|
|
} catch(e) {
|
|
next.become(new Rejected(e));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Same as above, but includes the extra argument parameter.
|
|
*/
|
|
function tryCatchReject3(f, x, y, thisArg, next) {
|
|
try {
|
|
f.call(thisArg, x, y, next);
|
|
} catch(e) {
|
|
next.become(new Rejected(e));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* Return f.call(thisArg, x), or if it throws, *return* the exception
|
|
*/
|
|
function tryCatchReturn(f, x, thisArg, next) {
|
|
try {
|
|
next.notify(f.call(thisArg, x));
|
|
} catch(e) {
|
|
next.notify(e);
|
|
}
|
|
}
|
|
|
|
function inherit(Parent, Child) {
|
|
Child.prototype = objectCreate(Parent.prototype);
|
|
Child.prototype.constructor = Child;
|
|
}
|
|
|
|
function snd(x, y) {
|
|
return y;
|
|
}
|
|
|
|
function noop() {}
|
|
|
|
function hasCustomEvent() {
|
|
if(typeof CustomEvent === 'function') {
|
|
try {
|
|
var ev = new CustomEvent('unhandledRejection');
|
|
return ev instanceof CustomEvent;
|
|
} catch (ignoredException) {}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function hasInternetExplorerCustomEvent() {
|
|
if(typeof document !== 'undefined' && typeof document.createEvent === 'function') {
|
|
try {
|
|
// Try to create one event to make sure it's supported
|
|
var ev = document.createEvent('CustomEvent');
|
|
ev.initCustomEvent('eventType', false, true, {});
|
|
return true;
|
|
} catch (ignoredException) {}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function initEmitRejection() {
|
|
/*global process, self, CustomEvent*/
|
|
if(typeof process !== 'undefined' && process !== null
|
|
&& typeof process.emit === 'function') {
|
|
// Returning falsy here means to call the default
|
|
// onPotentiallyUnhandledRejection API. This is safe even in
|
|
// browserify since process.emit always returns falsy in browserify:
|
|
// https://github.com/defunctzombie/node-process/blob/master/browser.js#L40-L46
|
|
return function(type, rejection) {
|
|
return type === 'unhandledRejection'
|
|
? process.emit(type, rejection.value, rejection)
|
|
: process.emit(type, rejection);
|
|
};
|
|
} else if(typeof self !== 'undefined' && hasCustomEvent()) {
|
|
return (function (self, CustomEvent) {
|
|
return function (type, rejection) {
|
|
var ev = new CustomEvent(type, {
|
|
detail: {
|
|
reason: rejection.value,
|
|
key: rejection
|
|
},
|
|
bubbles: false,
|
|
cancelable: true
|
|
});
|
|
|
|
return !self.dispatchEvent(ev);
|
|
};
|
|
}(self, CustomEvent));
|
|
} else if(typeof self !== 'undefined' && hasInternetExplorerCustomEvent()) {
|
|
return (function(self, document) {
|
|
return function(type, rejection) {
|
|
var ev = document.createEvent('CustomEvent');
|
|
ev.initCustomEvent(type, false, true, {
|
|
reason: rejection.value,
|
|
key: rejection
|
|
});
|
|
|
|
return !self.dispatchEvent(ev);
|
|
};
|
|
}(self, document));
|
|
}
|
|
|
|
return noop;
|
|
}
|
|
|
|
return Promise;
|
|
};
|
|
});
|
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|