UNPKG

faye

Version:

Simple pub/sub messaging for the web

173 lines (132 loc) 3.72 kB
'use strict'; var asap = require('asap'); var PENDING = -1, FULFILLED = 0, REJECTED = 1; var Promise = function(task) { this._state = PENDING; this._value = null; this._defer = []; execute(this, task); }; Promise.prototype.then = function(onFulfilled, onRejected) { var promise = new Promise(); var deferred = { promise: promise, onFulfilled: onFulfilled, onRejected: onRejected }; if (this._state === PENDING) this._defer.push(deferred); else propagate(this, deferred); return promise; }; Promise.prototype['catch'] = function(onRejected) { return this.then(null, onRejected); }; var execute = function(promise, task) { if (typeof task !== 'function') return; var calls = 0; var resolvePromise = function(value) { if (calls++ === 0) resolve(promise, value); }; var rejectPromise = function(reason) { if (calls++ === 0) reject(promise, reason); }; try { task(resolvePromise, rejectPromise); } catch (error) { rejectPromise(error); } }; var propagate = function(promise, deferred) { var state = promise._state, value = promise._value, next = deferred.promise, handler = [deferred.onFulfilled, deferred.onRejected][state], pass = [resolve, reject][state]; if (typeof handler !== 'function') return pass(next, value); asap(function() { try { resolve(next, handler(value)); } catch (error) { reject(next, error); } }); }; var resolve = function(promise, value) { if (promise === value) return reject(promise, new TypeError('Recursive promise chain detected')); var then; try { then = getThen(value); } catch (error) { return reject(promise, error); } if (!then) return fulfill(promise, value); execute(promise, function(resolvePromise, rejectPromise) { then.call(value, resolvePromise, rejectPromise); }); }; var getThen = function(value) { var type = typeof value, then = (type === 'object' || type === 'function') && value && value.then; return (typeof then === 'function') ? then : null; }; var fulfill = function(promise, value) { settle(promise, FULFILLED, value); }; var reject = function(promise, reason) { settle(promise, REJECTED, reason); }; var settle = function(promise, state, value) { var defer = promise._defer, i = 0; promise._state = state; promise._value = value; promise._defer = null; if (defer.length === 0) return; while (i < defer.length) propagate(promise, defer[i++]); }; Promise.resolve = function(value) { try { if (getThen(value)) return value; } catch (error) { return Promise.reject(error); } return new Promise(function(resolve, reject) { resolve(value) }); }; Promise.reject = function(reason) { return new Promise(function(resolve, reject) { reject(reason) }); }; Promise.all = function(promises) { return new Promise(function(resolve, reject) { var list = [], n = promises.length, i; if (n === 0) return resolve(list); var push = function(promise, i) { Promise.resolve(promise).then(function(value) { list[i] = value; if (--n === 0) resolve(list); }, reject); }; for (i = 0; i < n; i++) push(promises[i], i); }); }; Promise.race = function(promises) { return new Promise(function(resolve, reject) { for (var i = 0, n = promises.length; i < n; i++) Promise.resolve(promises[i]).then(resolve, reject); }); }; Promise.deferred = function() { var tuple = {}; tuple.promise = new Promise(function(resolve, reject) { tuple.resolve = resolve; tuple.reject = reject; }); return tuple; }; module.exports = Promise;