161 lines
4.7 KiB
JavaScript
161 lines
4.7 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 flow(Promise) {
|
||
|
|
||
|
var resolve = Promise.resolve;
|
||
|
var reject = Promise.reject;
|
||
|
var origCatch = Promise.prototype['catch'];
|
||
|
|
||
|
/**
|
||
|
* Handle the ultimate fulfillment value or rejection reason, and assume
|
||
|
* responsibility for all errors. If an error propagates out of result
|
||
|
* or handleFatalError, it will be rethrown to the host, resulting in a
|
||
|
* loud stack track on most platforms and a crash on some.
|
||
|
* @param {function?} onResult
|
||
|
* @param {function?} onError
|
||
|
* @returns {undefined}
|
||
|
*/
|
||
|
Promise.prototype.done = function(onResult, onError) {
|
||
|
this._handler.visit(this._handler.receiver, onResult, onError);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Add Error-type and predicate matching to catch. Examples:
|
||
|
* promise.catch(TypeError, handleTypeError)
|
||
|
* .catch(predicate, handleMatchedErrors)
|
||
|
* .catch(handleRemainingErrors)
|
||
|
* @param onRejected
|
||
|
* @returns {*}
|
||
|
*/
|
||
|
Promise.prototype['catch'] = Promise.prototype.otherwise = function(onRejected) {
|
||
|
if (arguments.length < 2) {
|
||
|
return origCatch.call(this, onRejected);
|
||
|
}
|
||
|
|
||
|
if(typeof onRejected !== 'function') {
|
||
|
return this.ensure(rejectInvalidPredicate);
|
||
|
}
|
||
|
|
||
|
return origCatch.call(this, createCatchFilter(arguments[1], onRejected));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Wraps the provided catch handler, so that it will only be called
|
||
|
* if the predicate evaluates truthy
|
||
|
* @param {?function} handler
|
||
|
* @param {function} predicate
|
||
|
* @returns {function} conditional catch handler
|
||
|
*/
|
||
|
function createCatchFilter(handler, predicate) {
|
||
|
return function(e) {
|
||
|
return evaluatePredicate(e, predicate)
|
||
|
? handler.call(this, e)
|
||
|
: reject(e);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensures that onFulfilledOrRejected will be called regardless of whether
|
||
|
* this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT
|
||
|
* receive the promises' value or reason. Any returned value will be disregarded.
|
||
|
* onFulfilledOrRejected may throw or return a rejected promise to signal
|
||
|
* an additional error.
|
||
|
* @param {function} handler handler to be called regardless of
|
||
|
* fulfillment or rejection
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
Promise.prototype['finally'] = Promise.prototype.ensure = function(handler) {
|
||
|
if(typeof handler !== 'function') {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
return this.then(function(x) {
|
||
|
return runSideEffect(handler, this, identity, x);
|
||
|
}, function(e) {
|
||
|
return runSideEffect(handler, this, reject, e);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
function runSideEffect (handler, thisArg, propagate, value) {
|
||
|
var result = handler.call(thisArg);
|
||
|
return maybeThenable(result)
|
||
|
? propagateValue(result, propagate, value)
|
||
|
: propagate(value);
|
||
|
}
|
||
|
|
||
|
function propagateValue (result, propagate, x) {
|
||
|
return resolve(result).then(function () {
|
||
|
return propagate(x);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Recover from a failure by returning a defaultValue. If defaultValue
|
||
|
* is a promise, it's fulfillment value will be used. If defaultValue is
|
||
|
* a promise that rejects, the returned promise will reject with the
|
||
|
* same reason.
|
||
|
* @param {*} defaultValue
|
||
|
* @returns {Promise} new promise
|
||
|
*/
|
||
|
Promise.prototype['else'] = Promise.prototype.orElse = function(defaultValue) {
|
||
|
return this.then(void 0, function() {
|
||
|
return defaultValue;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Shortcut for .then(function() { return value; })
|
||
|
* @param {*} value
|
||
|
* @return {Promise} a promise that:
|
||
|
* - is fulfilled if value is not a promise, or
|
||
|
* - if value is a promise, will fulfill with its value, or reject
|
||
|
* with its reason.
|
||
|
*/
|
||
|
Promise.prototype['yield'] = function(value) {
|
||
|
return this.then(function() {
|
||
|
return value;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Runs a side effect when this promise fulfills, without changing the
|
||
|
* fulfillment value.
|
||
|
* @param {function} onFulfilledSideEffect
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
Promise.prototype.tap = function(onFulfilledSideEffect) {
|
||
|
return this.then(onFulfilledSideEffect)['yield'](this);
|
||
|
};
|
||
|
|
||
|
return Promise;
|
||
|
};
|
||
|
|
||
|
function rejectInvalidPredicate() {
|
||
|
throw new TypeError('catch predicate must be a function');
|
||
|
}
|
||
|
|
||
|
function evaluatePredicate(e, predicate) {
|
||
|
return isError(predicate) ? e instanceof predicate : predicate(e);
|
||
|
}
|
||
|
|
||
|
function isError(predicate) {
|
||
|
return predicate === Error
|
||
|
|| (predicate != null && predicate.prototype instanceof Error);
|
||
|
}
|
||
|
|
||
|
function maybeThenable(x) {
|
||
|
return (typeof x === 'object' || typeof x === 'function') && x !== null;
|
||
|
}
|
||
|
|
||
|
function identity(x) {
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
});
|
||
|
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|