'use strict'; //This file contains then/promise specific extensions to the core promise API var Promise = require('./core.js') var asap = require('asap') module.exports = Promise /* Static Functions */ function ValuePromise(value) { this.then = function (onFulfilled) { if (typeof onFulfilled !== 'function') return this return new Promise(function (resolve, reject) { asap(function () { try { resolve(onFulfilled(value)) } catch (ex) { reject(ex); } }) }) } } ValuePromise.prototype = Object.create(Promise.prototype) var TRUE = new ValuePromise(true) var FALSE = new ValuePromise(false) var NULL = new ValuePromise(null) var UNDEFINED = new ValuePromise(undefined) var ZERO = new ValuePromise(0) var EMPTYSTRING = new ValuePromise('') Promise.resolve = function (value) { if (value instanceof Promise) return value if (value === null) return NULL if (value === undefined) return UNDEFINED if (value === true) return TRUE if (value === false) return FALSE if (value === 0) return ZERO if (value === '') return EMPTYSTRING if (typeof value === 'object' || typeof value === 'function') { try { var then = value.then if (typeof then === 'function') { return new Promise(then.bind(value)) } } catch (ex) { return new Promise(function (resolve, reject) { reject(ex) }) } } return new ValuePromise(value) } Promise.from = Promise.cast = function (value) { var err = new Error('Promise.from and Promise.cast are deprecated, use Promise.resolve instead') err.name = 'Warning' console.warn(err.stack) return Promise.resolve(value) } Promise.denodeify = function (fn, argumentCount) { argumentCount = argumentCount || Infinity return function () { var self = this var args = Array.prototype.slice.call(arguments) return new Promise(function (resolve, reject) { while (args.length && args.length > argumentCount) { args.pop() } args.push(function (err, res) { if (err) reject(err) else resolve(res) }) fn.apply(self, args) }) } } Promise.nodeify = function (fn) { return function () { var args = Array.prototype.slice.call(arguments) var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null try { return fn.apply(this, arguments).nodeify(callback) } catch (ex) { if (callback === null || typeof callback == 'undefined') { return new Promise(function (resolve, reject) { reject(ex) }) } else { asap(function () { callback(ex) }) } } } } Promise.all = function () { var calledWithArray = arguments.length === 1 && Array.isArray(arguments[0]) var args = Array.prototype.slice.call(calledWithArray ? arguments[0] : arguments) if (!calledWithArray) { var err = new Error('Promise.all should be called with a single array, calling it with multiple arguments is deprecated') err.name = 'Warning' console.warn(err.stack) } return new Promise(function (resolve, reject) { if (args.length === 0) return resolve([]) var remaining = args.length function res(i, val) { try { if (val && (typeof val === 'object' || typeof val === 'function')) { var then = val.then if (typeof then === 'function') { then.call(val, function (val) { res(i, val) }, reject) return } } args[i] = val if (--remaining === 0) { resolve(args); } } catch (ex) { reject(ex) } } for (var i = 0; i < args.length; i++) { res(i, args[i]) } }) } Promise.reject = function (value) { return new Promise(function (resolve, reject) { reject(value); }); } Promise.race = function (values) { return new Promise(function (resolve, reject) { values.forEach(function(value){ Promise.resolve(value).then(resolve, reject); }) }); } /* Prototype Methods */ Promise.prototype.done = function (onFulfilled, onRejected) { var self = arguments.length ? this.then.apply(this, arguments) : this self.then(null, function (err) { asap(function () { throw err }) }) } Promise.prototype.nodeify = function (callback) { if (typeof callback != 'function') return this this.then(function (value) { asap(function () { callback(null, value) }) }, function (err) { asap(function () { callback(err) }) }) } Promise.prototype['catch'] = function (onRejected) { return this.then(null, onRejected); }