joannangx/visionaria_app

View on GitHub
node_modules/pinkie/index.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict';

var PENDING = 'pending';
var SETTLED = 'settled';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
var NOOP = function () {};
var isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function';

var asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate;
var asyncQueue = [];
var asyncTimer;

function asyncFlush() {
    // run promise callbacks
    for (var i = 0; i < asyncQueue.length; i++) {
        asyncQueue[i][0](asyncQueue[i][1]);
    }

    // reset async asyncQueue
    asyncQueue = [];
    asyncTimer = false;
}

function asyncCall(callback, arg) {
    asyncQueue.push([callback, arg]);

    if (!asyncTimer) {
        asyncTimer = true;
        asyncSetTimer(asyncFlush, 0);
    }
}

function invokeResolver(resolver, promise) {
    function resolvePromise(value) {
        resolve(promise, value);
    }

    function rejectPromise(reason) {
        reject(promise, reason);
    }

    try {
        resolver(resolvePromise, rejectPromise);
    } catch (e) {
        rejectPromise(e);
    }
}

function invokeCallback(subscriber) {
    var owner = subscriber.owner;
    var settled = owner._state;
    var value = owner._data;
    var callback = subscriber[settled];
    var promise = subscriber.then;

    if (typeof callback === 'function') {
        settled = FULFILLED;
        try {
            value = callback(value);
        } catch (e) {
            reject(promise, e);
        }
    }

    if (!handleThenable(promise, value)) {
        if (settled === FULFILLED) {
            resolve(promise, value);
        }

        if (settled === REJECTED) {
            reject(promise, value);
        }
    }
}

function handleThenable(promise, value) {
    var resolved;

    try {
        if (promise === value) {
            throw new TypeError('A promises callback cannot return that same promise.');
        }

        if (value && (typeof value === 'function' || typeof value === 'object')) {
            // then should be retrieved only once
            var then = value.then;

            if (typeof then === 'function') {
                then.call(value, function (val) {
                    if (!resolved) {
                        resolved = true;

                        if (value === val) {
                            fulfill(promise, val);
                        } else {
                            resolve(promise, val);
                        }
                    }
                }, function (reason) {
                    if (!resolved) {
                        resolved = true;

                        reject(promise, reason);
                    }
                });

                return true;
            }
        }
    } catch (e) {
        if (!resolved) {
            reject(promise, e);
        }

        return true;
    }

    return false;
}

function resolve(promise, value) {
    if (promise === value || !handleThenable(promise, value)) {
        fulfill(promise, value);
    }
}

function fulfill(promise, value) {
    if (promise._state === PENDING) {
        promise._state = SETTLED;
        promise._data = value;

        asyncCall(publishFulfillment, promise);
    }
}

function reject(promise, reason) {
    if (promise._state === PENDING) {
        promise._state = SETTLED;
        promise._data = reason;

        asyncCall(publishRejection, promise);
    }
}

function publish(promise) {
    promise._then = promise._then.forEach(invokeCallback);
}

function publishFulfillment(promise) {
    promise._state = FULFILLED;
    publish(promise);
}

function publishRejection(promise) {
    promise._state = REJECTED;
    publish(promise);
    if (!promise._handled && isNode) {
        global.process.emit('unhandledRejection', promise._data, promise);
    }
}

function notifyRejectionHandled(promise) {
    global.process.emit('rejectionHandled', promise);
}

/**
 * @class
 */
function Promise(resolver) {
    if (typeof resolver !== 'function') {
        throw new TypeError('Promise resolver ' + resolver + ' is not a function');
    }

    if (this instanceof Promise === false) {
        throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');
    }

    this._then = [];

    invokeResolver(resolver, this);
}

Promise.prototype = {
    constructor: Promise,

    _state: PENDING,
    _then: null,
    _data: undefined,
    _handled: false,

    then: function (onFulfillment, onRejection) {
        var subscriber = {
            owner: this,
            then: new this.constructor(NOOP),
            fulfilled: onFulfillment,
            rejected: onRejection
        };

        if ((onRejection || onFulfillment) && !this._handled) {
            this._handled = true;
            if (this._state === REJECTED && isNode) {
                asyncCall(notifyRejectionHandled, this);
            }
        }

        if (this._state === FULFILLED || this._state === REJECTED) {
            // already resolved, call callback async
            asyncCall(invokeCallback, subscriber);
        } else {
            // subscribe
            this._then.push(subscriber);
        }

        return subscriber.then;
    },

    catch: function (onRejection) {
        return this.then(null, onRejection);
    }
};

Promise.all = function (promises) {
    if (!Array.isArray(promises)) {
        throw new TypeError('You must pass an array to Promise.all().');
    }

    return new Promise(function (resolve, reject) {
        var results = [];
        var remaining = 0;

        function resolver(index) {
            remaining++;
            return function (value) {
                results[index] = value;
                if (!--remaining) {
                    resolve(results);
                }
            };
        }

        for (var i = 0, promise; i < promises.length; i++) {
            promise = promises[i];

            if (promise && typeof promise.then === 'function') {
                promise.then(resolver(i), reject);
            } else {
                results[i] = promise;
            }
        }

        if (!remaining) {
            resolve(results);
        }
    });
};

Promise.race = function (promises) {
    if (!Array.isArray(promises)) {
        throw new TypeError('You must pass an array to Promise.race().');
    }

    return new Promise(function (resolve, reject) {
        for (var i = 0, promise; i < promises.length; i++) {
            promise = promises[i];

            if (promise && typeof promise.then === 'function') {
                promise.then(resolve, reject);
            } else {
                resolve(promise);
            }
        }
    });
};

Promise.resolve = function (value) {
    if (value && typeof value === 'object' && value.constructor === Promise) {
        return value;
    }

    return new Promise(function (resolve) {
        resolve(value);
    });
};

Promise.reject = function (reason) {
    return new Promise(function (resolve, reject) {
        reject(reason);
    });
};

module.exports = Promise;