Comparing version 3.0.3 to 3.0.4
# Master | ||
* Changes to RSVP.denodeify: Behaviour for multiple success callback parameters | ||
has been improved and the denodefied function now inherits from the original | ||
node function. | ||
# 3.0.2 | ||
@@ -91,3 +95,3 @@ | ||
* Fix infinite recursion with deep self fulfilling promises | ||
* doc fixes | ||
* doc fixes | ||
@@ -94,0 +98,0 @@ # 2.0.0 |
@@ -9,2 +9,3 @@ "use strict"; | ||
var hash = require("./rsvp/hash")["default"]; | ||
var hashSettled = require("./rsvp/hash_settled")["default"]; | ||
var rethrow = require("./rsvp/rethrow")["default"]; | ||
@@ -51,2 +52,3 @@ var defer = require("./rsvp/defer")["default"]; | ||
exports.hash = hash; | ||
exports.hashSettled = hashSettled; | ||
exports.rethrow = rethrow; | ||
@@ -53,0 +55,0 @@ exports.defer = defer; |
@@ -1,6 +0,5 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
var isArray = require("./utils").isArray; | ||
var isNonThenable = require("./utils").isNonThenable; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
var isArray = require('./utils').isArray; | ||
var isNonThenable = require('./utils').isNonThenable; | ||
/** | ||
@@ -48,5 +47,6 @@ `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing | ||
@method @allSettled | ||
@method allSettled | ||
@static | ||
@for RSVP | ||
@param {Array} promises; | ||
@param {Array} promises | ||
@param {String} label - optional string that describes the promise. | ||
@@ -57,56 +57,51 @@ Useful for tooling. | ||
*/ | ||
exports["default"] = function allSettled(entries, label) { | ||
return new Promise(function(resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to allSettled.'); | ||
} | ||
var remaining = entries.length; | ||
var entry; | ||
if (remaining === 0) { | ||
resolve([]); | ||
return; | ||
} | ||
var results = new Array(remaining); | ||
function fulfilledResolver(index) { | ||
return function(value) { | ||
resolveAll(index, fulfilled(value)); | ||
}; | ||
} | ||
function rejectedResolver(index) { | ||
return function(reason) { | ||
resolveAll(index, rejected(reason)); | ||
}; | ||
} | ||
function resolveAll(index, value) { | ||
results[index] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
} | ||
for (var index = 0; index < entries.length; index++) { | ||
entry = entries[index]; | ||
if (isNonThenable(entry)) { | ||
resolveAll(index, fulfilled(entry)); | ||
} else { | ||
Promise.cast(entry).then(fulfilledResolver(index), rejectedResolver(index)); | ||
} | ||
} | ||
}, label); | ||
exports['default'] = function allSettled(entries, label) { | ||
return new Promise(function (resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to allSettled.'); | ||
} | ||
var remaining = entries.length; | ||
var entry; | ||
if (remaining === 0) { | ||
resolve([]); | ||
return; | ||
} | ||
var results = new Array(remaining); | ||
function fulfilledResolver(index) { | ||
return function (value) { | ||
resolveAll(index, fulfilled(value)); | ||
}; | ||
} | ||
function rejectedResolver(index) { | ||
return function (reason) { | ||
resolveAll(index, rejected(reason)); | ||
}; | ||
} | ||
function resolveAll(index, value) { | ||
results[index] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
} | ||
for (var index = 0; index < entries.length; index++) { | ||
entry = entries[index]; | ||
if (isNonThenable(entry)) { | ||
resolveAll(index, fulfilled(entry)); | ||
} else { | ||
Promise.resolve(entry).then(fulfilledResolver(index), rejectedResolver(index)); | ||
} | ||
} | ||
}, label); | ||
}; | ||
function fulfilled(value) { | ||
return { state: 'fulfilled', value: value }; | ||
return { | ||
state: 'fulfilled', | ||
value: value | ||
}; | ||
} | ||
function rejected(reason) { | ||
return { state: 'rejected', reason: reason }; | ||
return { | ||
state: 'rejected', | ||
reason: reason | ||
}; | ||
} |
@@ -1,6 +0,15 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.all`. | ||
exports["default"] = function all(array, label) { | ||
return Promise.all(array, label); | ||
@method all | ||
@static | ||
@for RSVP | ||
@param {Array} array Array of promises. | ||
@param {String} label An optional label. This is useful | ||
for tooling. | ||
*/ | ||
exports['default'] = function all(array, label) { | ||
return Promise.all(array, label); | ||
}; |
@@ -1,58 +0,53 @@ | ||
"use strict"; | ||
exports["default"] = function asap(callback, arg) { | ||
var length = queue.push([callback, arg]); | ||
if (length === 1) { | ||
// If length is 1, that means that we need to schedule an async flush. | ||
// If additional callbacks are queued before the queue is flushed, they | ||
// will be processed by this flush that we are scheduling. | ||
scheduleFlush(); | ||
} | ||
'use strict'; | ||
exports['default'] = function asap(callback, arg) { | ||
var length = queue.push([ | ||
callback, | ||
arg | ||
]); | ||
if (length === 1) { | ||
// If length is 1, that means that we need to schedule an async flush. | ||
// If additional callbacks are queued before the queue is flushed, they | ||
// will be processed by this flush that we are scheduling. | ||
scheduleFlush(); | ||
} | ||
}; | ||
var browserGlobal = (typeof window !== 'undefined') ? window : {}; | ||
var browserGlobal = typeof window !== 'undefined' ? window : {}; | ||
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; | ||
// node | ||
function useNextTick() { | ||
return function() { | ||
process.nextTick(flush); | ||
}; | ||
return function () { | ||
process.nextTick(flush); | ||
}; | ||
} | ||
function useMutationObserver() { | ||
var iterations = 0; | ||
var observer = new BrowserMutationObserver(flush); | ||
var node = document.createTextNode(''); | ||
observer.observe(node, { characterData: true }); | ||
return function() { | ||
node.data = (iterations = ++iterations % 2); | ||
}; | ||
var iterations = 0; | ||
var observer = new BrowserMutationObserver(flush); | ||
var node = document.createTextNode(''); | ||
observer.observe(node, { characterData: true }); | ||
return function () { | ||
node.data = iterations = ++iterations % 2; | ||
}; | ||
} | ||
function useSetTimeout() { | ||
return function() { | ||
setTimeout(flush, 1); | ||
}; | ||
return function () { | ||
setTimeout(flush, 1); | ||
}; | ||
} | ||
var queue = []; | ||
function flush() { | ||
for (var i = 0; i < queue.length; i++) { | ||
var tuple = queue[i]; | ||
var callback = tuple[0], arg = tuple[1]; | ||
callback(arg); | ||
} | ||
queue = []; | ||
for (var i = 0; i < queue.length; i++) { | ||
var tuple = queue[i]; | ||
var callback = tuple[0], arg = tuple[1]; | ||
callback(arg); | ||
} | ||
queue = []; | ||
} | ||
var scheduleFlush; | ||
// Decide what async method to use to triggering processing of queued callbacks: | ||
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { | ||
scheduleFlush = useNextTick(); | ||
scheduleFlush = useNextTick(); | ||
} else if (BrowserMutationObserver) { | ||
scheduleFlush = useMutationObserver(); | ||
scheduleFlush = useMutationObserver(); | ||
} else { | ||
scheduleFlush = useSetTimeout(); | ||
scheduleFlush = useSetTimeout(); | ||
} |
@@ -1,27 +0,20 @@ | ||
"use strict"; | ||
var EventTarget = require("./events")["default"]; | ||
var config = { | ||
instrument: false | ||
}; | ||
'use strict'; | ||
var EventTarget = require('./events')['default']; | ||
var config = { instrument: false }; | ||
EventTarget.mixin(config); | ||
function configure(name, value) { | ||
if (name === 'onerror') { | ||
// handle for legacy users that expect the actual | ||
// error to be passed to their function added via | ||
// `RSVP.configure('onerror', someFunctionHere);` | ||
config.on('error', value); | ||
return; | ||
} | ||
if (arguments.length === 2) { | ||
config[name] = value; | ||
} else { | ||
return config[name]; | ||
} | ||
if (name === 'onerror') { | ||
// handle for legacy users that expect the actual | ||
// error to be passed to their function added via | ||
// `RSVP.configure('onerror', someFunctionHere);` | ||
config.on('error', value); | ||
return; | ||
} | ||
if (arguments.length === 2) { | ||
config[name] = value; | ||
} else { | ||
return config[name]; | ||
} | ||
} | ||
exports.config = config; | ||
exports.configure = configure; |
@@ -1,4 +0,3 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
/** | ||
@@ -30,2 +29,3 @@ `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. | ||
@method defer | ||
@static | ||
@for RSVP | ||
@@ -36,12 +36,9 @@ @param {String} label optional string for labeling the promise. | ||
*/ | ||
exports["default"] = function defer(label) { | ||
var deferred = { }; | ||
deferred.promise = new Promise(function(resolve, reject) { | ||
deferred.resolve = resolve; | ||
deferred.reject = reject; | ||
}, label); | ||
return deferred; | ||
exports['default'] = function defer(label) { | ||
var deferred = {}; | ||
deferred.promise = new Promise(function (resolve, reject) { | ||
deferred.resolve = resolve; | ||
deferred.reject = reject; | ||
}, label); | ||
return deferred; | ||
}; |
@@ -1,201 +0,60 @@ | ||
"use strict"; | ||
var indexOf = function(callbacks, callback) { | ||
for (var i=0, l=callbacks.length; i<l; i++) { | ||
if (callbacks[i] === callback) { return i; } | ||
} | ||
return -1; | ||
'use strict'; | ||
var indexOf = function (callbacks, callback) { | ||
for (var i = 0, l = callbacks.length; i < l; i++) { | ||
if (callbacks[i] === callback) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
}; | ||
var callbacksFor = function(object) { | ||
var callbacks = object._promiseCallbacks; | ||
if (!callbacks) { | ||
callbacks = object._promiseCallbacks = {}; | ||
} | ||
return callbacks; | ||
var callbacksFor = function (object) { | ||
var callbacks = object._promiseCallbacks; | ||
if (!callbacks) { | ||
callbacks = object._promiseCallbacks = {}; | ||
} | ||
return callbacks; | ||
}; | ||
/** | ||
//@module RSVP | ||
//@class EventTarget | ||
@class RSVP.EventTarget | ||
*/ | ||
exports["default"] = { | ||
/** | ||
`RSVP.EventTarget.mixin` extends an object with EventTarget methods. For | ||
Example: | ||
```javascript | ||
var object = {}; | ||
RSVP.EventTarget.mixin(object); | ||
object.on("finished", function(event) { | ||
// handle event | ||
}); | ||
object.trigger("finished", { detail: value }); | ||
``` | ||
`EventTarget.mixin` also works with prototypes: | ||
```javascript | ||
var Person = function() {}; | ||
RSVP.EventTarget.mixin(Person.prototype); | ||
var yehuda = new Person(); | ||
var tom = new Person(); | ||
yehuda.on("poke", function(event) { | ||
console.log("Yehuda says OW"); | ||
}); | ||
tom.on("poke", function(event) { | ||
console.log("Tom says OW"); | ||
}); | ||
yehuda.trigger("poke"); | ||
tom.trigger("poke"); | ||
``` | ||
@method mixin | ||
@param {Object} object object to extend with EventTarget methods | ||
@private | ||
*/ | ||
mixin: function(object) { | ||
object.on = this.on; | ||
object.off = this.off; | ||
object.trigger = this.trigger; | ||
object._promiseCallbacks = undefined; | ||
return object; | ||
}, | ||
/** | ||
Registers a callback to be executed when `eventName` is triggered | ||
```javascript | ||
object.on('event', function(eventInfo){ | ||
// handle the event | ||
}); | ||
object.trigger('event'); | ||
``` | ||
@method on | ||
@param {String} eventName name of the event to listen for | ||
@param {Function} callback function to be called when the event is triggered. | ||
@private | ||
*/ | ||
on: function(eventName, callback) { | ||
var allCallbacks = callbacksFor(this), callbacks; | ||
callbacks = allCallbacks[eventName]; | ||
if (!callbacks) { | ||
callbacks = allCallbacks[eventName] = []; | ||
exports['default'] = { | ||
mixin: function (object) { | ||
object.on = this.on; | ||
object.off = this.off; | ||
object.trigger = this.trigger; | ||
object._promiseCallbacks = undefined; | ||
return object; | ||
}, | ||
on: function (eventName, callback) { | ||
var allCallbacks = callbacksFor(this), callbacks; | ||
callbacks = allCallbacks[eventName]; | ||
if (!callbacks) { | ||
callbacks = allCallbacks[eventName] = []; | ||
} | ||
if (indexOf(callbacks, callback) === -1) { | ||
callbacks.push(callback); | ||
} | ||
}, | ||
off: function (eventName, callback) { | ||
var allCallbacks = callbacksFor(this), callbacks, index; | ||
if (!callback) { | ||
allCallbacks[eventName] = []; | ||
return; | ||
} | ||
callbacks = allCallbacks[eventName]; | ||
index = indexOf(callbacks, callback); | ||
if (index !== -1) { | ||
callbacks.splice(index, 1); | ||
} | ||
}, | ||
trigger: function (eventName, options) { | ||
var allCallbacks = callbacksFor(this), callbacks, callbackTuple, callback, binding; | ||
if (callbacks = allCallbacks[eventName]) { | ||
// Don't cache the callbacks.length since it may grow | ||
for (var i = 0; i < callbacks.length; i++) { | ||
callback = callbacks[i]; | ||
callback(options); | ||
} | ||
} | ||
} | ||
if (indexOf(callbacks, callback) === -1) { | ||
callbacks.push(callback); | ||
} | ||
}, | ||
/** | ||
You can use `off` to stop firing a particular callback for an event: | ||
```javascript | ||
function doStuff() { // do stuff! } | ||
object.on('stuff', doStuff); | ||
object.trigger('stuff'); // doStuff will be called | ||
// Unregister ONLY the doStuff callback | ||
object.off('stuff', doStuff); | ||
object.trigger('stuff'); // doStuff will NOT be called | ||
``` | ||
If you don't pass a `callback` argument to `off`, ALL callbacks for the | ||
event will not be executed when the event fires. For example: | ||
```javascript | ||
var callback1 = function(){}; | ||
var callback2 = function(){}; | ||
object.on('stuff', callback1); | ||
object.on('stuff', callback2); | ||
object.trigger('stuff'); // callback1 and callback2 will be executed. | ||
object.off('stuff'); | ||
object.trigger('stuff'); // callback1 and callback2 will not be executed! | ||
``` | ||
@method off | ||
@param {String} eventName event to stop listening to | ||
@param {Function} callback optional argument. If given, only the function | ||
given will be removed from the event's callback queue. If no `callback` | ||
argument is given, all callbacks will be removed from the event's callback | ||
queue. | ||
@private | ||
*/ | ||
off: function(eventName, callback) { | ||
var allCallbacks = callbacksFor(this), callbacks, index; | ||
if (!callback) { | ||
allCallbacks[eventName] = []; | ||
return; | ||
} | ||
callbacks = allCallbacks[eventName]; | ||
index = indexOf(callbacks, callback); | ||
if (index !== -1) { callbacks.splice(index, 1); } | ||
}, | ||
/** | ||
Use `trigger` to fire custom events. For example: | ||
```javascript | ||
object.on('foo', function(){ | ||
console.log('foo event happened!'); | ||
}); | ||
object.trigger('foo'); | ||
// 'foo event happened!' logged to the console | ||
``` | ||
You can also pass a value as a second argument to `trigger` that will be | ||
passed as an argument to all event listeners for the event: | ||
```javascript | ||
object.on('foo', function(value){ | ||
console.log(value.name); | ||
}); | ||
object.trigger('foo', { name: 'bar' }); | ||
// 'bar' logged to the console | ||
``` | ||
@method trigger | ||
@param {String} eventName name of the event to be triggered | ||
@param {Any} options optional value to be passed to any event handlers for | ||
the given `eventName` | ||
@private | ||
*/ | ||
trigger: function(eventName, options) { | ||
var allCallbacks = callbacksFor(this), | ||
callbacks, callbackTuple, callback, binding; | ||
if (callbacks = allCallbacks[eventName]) { | ||
// Don't cache the callbacks.length since it may grow | ||
for (var i=0; i<callbacks.length; i++) { | ||
callback = callbacks[i]; | ||
callback(options); | ||
} | ||
} | ||
} | ||
}; |
@@ -1,7 +0,4 @@ | ||
"use strict"; | ||
var all = require("./all")["default"]; | ||
var map = require("./map")["default"]; | ||
var isFunction = require("./utils").isFunction; | ||
var isArray = require("./utils").isArray; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
var isFunction = require('./utils').isFunction; | ||
/** | ||
@@ -81,2 +78,3 @@ `RSVP.filter` is similar to JavaScript's native `filter` method, except that it | ||
@method filter | ||
@static | ||
@for RSVP | ||
@@ -90,25 +88,22 @@ @param {Array} promises | ||
*/ | ||
function filter(promises, filterFn, label) { | ||
return all(promises, label).then(function(values){ | ||
if (!isArray(promises)) { | ||
throw new TypeError('You must pass an array to filter.'); | ||
} | ||
if (!isFunction(filterFn)){ | ||
throw new TypeError("You must pass a function to filter's second argument."); | ||
} | ||
return map(promises, filterFn, label).then(function(filterResults){ | ||
var i, | ||
valuesLen = values.length, | ||
filtered = []; | ||
for (i = 0; i < valuesLen; i++){ | ||
if(filterResults[i]) filtered.push(values[i]); | ||
} | ||
return filtered; | ||
exports['default'] = function filter(promises, filterFn, label) { | ||
return Promise.all(promises, label).then(function (values) { | ||
if (!isFunction(filterFn)) { | ||
throw new TypeError('You must pass a function as filter\'s second argument.'); | ||
} | ||
var length = values.length; | ||
var filtered = new Array(length); | ||
for (var i = 0; i < length; i++) { | ||
filtered[i] = filterFn(values[i]); | ||
} | ||
return Promise.all(filtered, label).then(function (filtered$2) { | ||
var results = []; | ||
for (var i$2 = 0; i$2 < length; i$2++) { | ||
if (filtered$2[i$2] === true) { | ||
results.push(values[i$2]); | ||
} | ||
} | ||
return results; | ||
}); | ||
}); | ||
}); | ||
} | ||
exports["default"] = filter; | ||
}; |
@@ -1,6 +0,5 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
var isNonThenable = require("./utils").isNonThenable; | ||
var keysOf = require("./utils").keysOf; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
var isNonThenable = require('./utils').isNonThenable; | ||
var keysOf = require('./utils').keysOf; | ||
/** | ||
@@ -86,5 +85,6 @@ `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array | ||
@method hash | ||
@static | ||
@for RSVP | ||
@param {Object} promises | ||
@param {String} label - optional string that describes the promise. | ||
@param {String} label optional string that describes the promise. | ||
Useful for tooling. | ||
@@ -94,42 +94,37 @@ @return {Promise} promise that is fulfilled when all properties of `promises` | ||
*/ | ||
exports["default"] = function hash(object, label) { | ||
return new Promise(function(resolve, reject){ | ||
var results = {}; | ||
var keys = keysOf(object); | ||
var remaining = keys.length; | ||
var entry, property; | ||
if (remaining === 0) { | ||
resolve(results); | ||
return; | ||
} | ||
function fulfilledTo(property) { | ||
return function(value) { | ||
results[property] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
exports['default'] = function hash(object, label) { | ||
return new Promise(function (resolve, reject) { | ||
var results = {}; | ||
var keys = keysOf(object); | ||
var remaining = keys.length; | ||
var entry, property; | ||
if (remaining === 0) { | ||
resolve(results); | ||
return; | ||
} | ||
}; | ||
} | ||
function onRejection(reason) { | ||
remaining = 0; | ||
reject(reason); | ||
} | ||
for (var i = 0; i < keys.length; i++) { | ||
property = keys[i]; | ||
entry = object[property]; | ||
if (isNonThenable(entry)) { | ||
results[property] = entry; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
function fulfilledTo(property) { | ||
return function (value) { | ||
results[property] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
}; | ||
} | ||
} else { | ||
Promise.cast(entry).then(fulfilledTo(property), onRejection); | ||
} | ||
} | ||
}); | ||
function onRejection(reason) { | ||
remaining = 0; | ||
reject(reason); | ||
} | ||
for (var i = 0; i < keys.length; i++) { | ||
property = keys[i]; | ||
entry = object[property]; | ||
if (isNonThenable(entry)) { | ||
results[property] = entry; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
} else { | ||
Promise.resolve(entry).then(fulfilledTo(property), onRejection); | ||
} | ||
} | ||
}); | ||
}; |
@@ -1,22 +0,21 @@ | ||
"use strict"; | ||
var config = require("./config").config; | ||
var now = require("./utils").now; | ||
exports["default"] = function instrument(eventName, promise, child) { | ||
// instrumentation should not disrupt normal usage. | ||
try { | ||
config.trigger(eventName, { | ||
guid: promise._guidKey + promise._id, | ||
eventName: eventName, | ||
detail: promise._detail, | ||
childGuid: child && promise._guidKey + child._id, | ||
label: promise._label, | ||
timeStamp: now(), | ||
stack: new Error(promise._label).stack | ||
}); | ||
} catch(error) { | ||
setTimeout(function(){ | ||
throw error; | ||
}, 0); | ||
} | ||
'use strict'; | ||
var config = require('./config').config; | ||
var now = require('./utils').now; | ||
exports['default'] = function instrument(eventName, promise, child) { | ||
// instrumentation should not disrupt normal usage. | ||
try { | ||
config.trigger(eventName, { | ||
guid: promise._guidKey + promise._id, | ||
eventName: eventName, | ||
detail: promise._detail, | ||
childGuid: child && promise._guidKey + child._id, | ||
label: promise._label, | ||
timeStamp: now(), | ||
stack: new Error(promise._label).stack | ||
}); | ||
} catch (error) { | ||
setTimeout(function () { | ||
throw error; | ||
}, 0); | ||
} | ||
}; |
@@ -1,9 +0,6 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
var all = require("./all")["default"]; | ||
var isArray = require("./utils").isArray; | ||
var isFunction = require("./utils").isFunction; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
var isArray = require('./utils').isArray; | ||
var isFunction = require('./utils').isFunction; | ||
/** | ||
`RSVP.map` is similar to JavaScript's native `map` method, except that it | ||
@@ -75,2 +72,3 @@ waits for all promises to become fulfilled before running the `mapFn` on | ||
@method map | ||
@static | ||
@for RSVP | ||
@@ -84,24 +82,16 @@ @param {Array} promises | ||
The promise will be rejected if any of the given `promises` become rejected. | ||
@static | ||
*/ | ||
exports["default"] = function map(promises, mapFn, label) { | ||
return all(promises, label).then(function(results){ | ||
if (!isArray(promises)) { | ||
throw new TypeError('You must pass an array to map.'); | ||
} | ||
if (!isFunction(mapFn)){ | ||
throw new TypeError("You must pass a function to map's second argument."); | ||
} | ||
var resultLen = results.length, | ||
mappedResults = [], | ||
i; | ||
for (i = 0; i < resultLen; i++){ | ||
mappedResults.push(mapFn(results[i])); | ||
} | ||
return all(mappedResults, label); | ||
}); | ||
exports['default'] = function map(promises, mapFn, label) { | ||
return Promise.all(promises, label).then(function (values) { | ||
if (!isFunction(mapFn)) { | ||
throw new TypeError('You must pass a function as map\'s second argument.'); | ||
} | ||
var length = values.length; | ||
var results = new Array(length); | ||
for (var i = 0; i < length; i++) { | ||
results[i] = mapFn(values[i]); | ||
} | ||
return Promise.all(results, label); | ||
}); | ||
}; |
@@ -1,18 +0,5 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
var slice = Array.prototype.slice; | ||
function makeNodeCallbackFor(resolve, reject) { | ||
return function (error, value) { | ||
if (error) { | ||
reject(error); | ||
} else if (arguments.length > 2) { | ||
resolve(slice.call(arguments, 1)); | ||
} else { | ||
resolve(value); | ||
} | ||
}; | ||
} | ||
'use strict'; | ||
/* global $a_slice */ | ||
var Promise = require('./promise')['default']; | ||
var isArray = require('./utils').isArray; | ||
/** | ||
@@ -37,3 +24,2 @@ `RSVP.denodeify` takes a "node-style" function and returns a function that | ||
var fs = require('fs'); | ||
var readFile = RSVP.denodeify(fs.readFile); | ||
@@ -44,2 +30,58 @@ | ||
If the node function has multiple success parameters, then `denodeify` | ||
just returns the first one: | ||
```javascript | ||
var request = RSVP.denodeify(require('request')); | ||
request('http://example.com').then(function(res) { | ||
// ... | ||
}); | ||
``` | ||
However, if you need all success parameters, setting `denodeify`'s | ||
second parameter to `true` causes it to return all success parameters | ||
as an array: | ||
```javascript | ||
var request = RSVP.denodeify(require('request'), true); | ||
request('http://example.com').then(function(result) { | ||
// result[0] -> res | ||
// result[1] -> body | ||
}); | ||
``` | ||
Or if you pass it an array with names it returns the parameters as a hash: | ||
```javascript | ||
var request = RSVP.denodeify(require('request'), ['res', 'body']); | ||
request('http://example.com').then(function(result) { | ||
// result.res | ||
// result.body | ||
}); | ||
``` | ||
Sometimes you need to retain the `this`: | ||
```javascript | ||
var app = require('express')(); | ||
var render = RSVP.denodeify(app.render.bind(app)); | ||
``` | ||
The denodified function inherits from the original function. It works in all | ||
environments, except IE 10 and below. Consequently all properties of the original | ||
function are available to you. However, any properties you change on the | ||
denodeified function won't be changed on the original function. Example: | ||
```javascript | ||
var request = RSVP.denodeify(require('request')), | ||
cookieJar = request.jar(); // <- Inheritance is used here | ||
request('http://example.com', {jar: cookieJar}).then(function(res) { | ||
// cookieJar.cookies holds now the cookies returned by example.com | ||
}); | ||
``` | ||
Using `denodeify` makes it easier to compose asynchronous operations instead | ||
@@ -50,11 +92,8 @@ of using callbacks. For example, instead of: | ||
var fs = require('fs'); | ||
var log = require('some-async-logger'); | ||
fs.readFile('myfile.txt', function(err, data){ | ||
if (err) return handleError(err); | ||
if (err) { ... } // Handle error | ||
fs.writeFile('myfile2.txt', data, function(err){ | ||
if (err) throw err; | ||
log('success', function(err) { | ||
if (err) throw err; | ||
}); | ||
if (err) { ... } // Handle error | ||
console.log('done') | ||
}); | ||
@@ -64,10 +103,8 @@ }); | ||
You can chain the operations together using `then` from the returned promise: | ||
you can chain the operations together using `then` from the returned promise: | ||
```javascript | ||
var fs = require('fs'); | ||
var denodeify = RSVP.denodeify; | ||
var readFile = denodeify(fs.readFile); | ||
var writeFile = denodeify(fs.writeFile); | ||
var log = denodeify(require('some-async-logger')); | ||
var readFile = RSVP.denodeify(fs.readFile); | ||
var writeFile = RSVP.denodeify(fs.writeFile); | ||
@@ -77,7 +114,5 @@ readFile('myfile.txt').then(function(data){ | ||
}).then(function(){ | ||
return log('SUCCESS'); | ||
}).then(function(){ | ||
// success handler | ||
}, function(reason){ | ||
// rejection handler | ||
console.log('done') | ||
}).catch(function(error){ | ||
// Handle error | ||
}); | ||
@@ -87,2 +122,3 @@ ``` | ||
@method denodeify | ||
@static | ||
@for RSVP | ||
@@ -93,23 +129,71 @@ @param {Function} nodeFunc a "node-style" function that takes a callback as | ||
operation as its second argument ("function(err, value){ }"). | ||
@param {Any} binding optional argument for binding the "this" value when | ||
calling the `nodeFunc` function. | ||
@param {Boolean|Array} argumentNames An optional paramter that if set | ||
to `true` causes the promise to fulfill with the callback's success arguments | ||
as an array. This is useful if the node function has multiple success | ||
paramters. If you set this paramter to an array with names, the promise will | ||
fulfill with a hash with these names as keys and the success parameters as | ||
values. | ||
@return {Function} a function that wraps `nodeFunc` to return an | ||
`RSVP.Promise` | ||
@static | ||
*/ | ||
exports["default"] = function denodeify(nodeFunc, binding) { | ||
return function() { | ||
var nodeArgs = slice.call(arguments), resolve, reject; | ||
var thisArg = this || binding; | ||
return new Promise(function(resolve, reject) { | ||
Promise.all(nodeArgs).then(function(nodeArgs) { | ||
try { | ||
nodeArgs.push(makeNodeCallbackFor(resolve, reject)); | ||
nodeFunc.apply(thisArg, nodeArgs); | ||
} catch(e) { | ||
reject(e); | ||
exports['default'] = function denodeify(nodeFunc, argumentNames) { | ||
var asArray = argumentNames === true; | ||
var asHash = isArray(argumentNames); | ||
function denodeifiedFunction() { | ||
var nodeArgs; | ||
var length = arguments.length; | ||
nodeArgs = new Array(length); | ||
for (var i = 0; i < length; i++) { | ||
nodeArgs[i] = arguments[i]; | ||
} | ||
}); | ||
}); | ||
}; | ||
; | ||
var thisArg; | ||
if (!asArray && !asHash && argumentNames) { | ||
console.warn('Deprecation: RSVP.denodeify() doesn\'t allow setting the ' + '"this" binding anymore. Use yourFunction.bind(yourThis) instead.'); | ||
thisArg = argumentNames; | ||
} else { | ||
thisArg = this; | ||
} | ||
return Promise.all(nodeArgs).then(function (nodeArgs$2) { | ||
return new Promise(resolver); | ||
// sweet.js has a bug, this resolver can't defined in the constructor | ||
// or the $a_slice macro doesn't work | ||
function resolver(resolve, reject) { | ||
function callback() { | ||
var args; | ||
var length$2 = arguments.length; | ||
args = new Array(length$2); | ||
for (var i$2 = 0; i$2 < length$2; i$2++) { | ||
args[i$2] = arguments[i$2]; | ||
} | ||
; | ||
var error = args[0]; | ||
var value = args[1]; | ||
if (error) { | ||
reject(error); | ||
} else if (asArray) { | ||
resolve(args.slice(1)); | ||
} else if (asHash) { | ||
var obj = {}; | ||
var successArguments = args.slice(1); | ||
var name; | ||
var i$3; | ||
for (i$3 = 0; i$3 < argumentNames.length; i$3++) { | ||
name = argumentNames[i$3]; | ||
obj[name] = successArguments[i$3]; | ||
} | ||
resolve(obj); | ||
} else { | ||
resolve(value); | ||
} | ||
} | ||
nodeArgs$2.push(callback); | ||
nodeFunc.apply(thisArg, nodeArgs$2); | ||
} | ||
}); | ||
} | ||
; | ||
denodeifiedFunction.__proto__ = nodeFunc; | ||
return denodeifiedFunction; | ||
}; |
@@ -1,24 +0,19 @@ | ||
"use strict"; | ||
var config = require("./config").config; | ||
var EventTarget = require("./events")["default"]; | ||
var instrument = require("./instrument")["default"]; | ||
var objectOrFunction = require("./utils").objectOrFunction; | ||
var isFunction = require("./utils").isFunction; | ||
var now = require("./utils").now; | ||
var cast = require("./promise/cast")["default"]; | ||
var all = require("./promise/all")["default"]; | ||
var race = require("./promise/race")["default"]; | ||
var Resolve = require("./promise/resolve")["default"]; | ||
var Reject = require("./promise/reject")["default"]; | ||
'use strict'; | ||
var config = require('./config').config; | ||
var EventTarget = require('./events')['default']; | ||
var instrument = require('./instrument')['default']; | ||
var objectOrFunction = require('./utils').objectOrFunction; | ||
var isFunction = require('./utils').isFunction; | ||
var now = require('./utils').now; | ||
var cast = require('./promise/cast')['default']; | ||
var all = require('./promise/all')['default']; | ||
var race = require('./promise/race')['default']; | ||
var Resolve = require('./promise/resolve')['default']; | ||
var Reject = require('./promise/reject')['default']; | ||
var guidKey = 'rsvp_' + now() + '-'; | ||
var counter = 0; | ||
function noop() {} | ||
exports["default"] = Promise; | ||
function noop() { | ||
} | ||
exports['default'] = Promise; | ||
/** | ||
Promise objects represent the eventual result of an asynchronous operation. The | ||
@@ -41,3 +36,13 @@ primary way of interacting with a promise is through its `then` method, which | ||
Promises that are fulfilled have a fulfillment value and are in the fulfilled | ||
state. Promises that are rejected have a rejection reason and are in the | ||
rejected state. A fulfillment value is never a thenable. | ||
Promises can also be said to *resolve* a value. If this value is also a | ||
promise, then the original promise's settled state will match the value's | ||
settled state. So a promise that *resolves* a promise that rejects will | ||
itself reject, and a promise that *resolves* a promise that fulfills will | ||
itself fulfill. | ||
Basic Usage: | ||
@@ -112,3 +117,3 @@ ------------ | ||
@class Promise | ||
@class RSVP.Promise | ||
@param {function} | ||
@@ -120,39 +125,31 @@ @param {String} label optional string for labeling the promise. | ||
function Promise(resolver, label) { | ||
if (!isFunction(resolver)) { | ||
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); | ||
} | ||
if (!(this instanceof Promise)) { | ||
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); | ||
} | ||
this._id = counter++; | ||
this._label = label; | ||
this._subscribers = []; | ||
if (config.instrument) { | ||
instrument('created', this); | ||
} | ||
if (noop !== resolver) { | ||
invokeResolver(resolver, this); | ||
} | ||
if (!isFunction(resolver)) { | ||
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); | ||
} | ||
if (!(this instanceof Promise)) { | ||
throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.'); | ||
} | ||
this._id = counter++; | ||
this._label = label; | ||
this._subscribers = []; | ||
if (config.instrument) { | ||
instrument('created', this); | ||
} | ||
if (noop !== resolver) { | ||
invokeResolver(resolver, this); | ||
} | ||
} | ||
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 resolvePromise(value) { | ||
resolve(promise, value); | ||
} | ||
function rejectPromise(reason) { | ||
reject(promise, reason); | ||
} | ||
try { | ||
resolver(resolvePromise, rejectPromise); | ||
} catch (e) { | ||
rejectPromise(e); | ||
} | ||
} | ||
Promise.cast = cast; | ||
@@ -163,461 +160,164 @@ Promise.all = all; | ||
Promise.reject = Reject; | ||
var PENDING = void 0; | ||
var SEALED = 0; | ||
var PENDING = void 0; | ||
var SEALED = 0; | ||
var FULFILLED = 1; | ||
var REJECTED = 2; | ||
var REJECTED = 2; | ||
function subscribe(parent, child, onFulfillment, onRejection) { | ||
var subscribers = parent._subscribers; | ||
var length = subscribers.length; | ||
subscribers[length] = child; | ||
subscribers[length + FULFILLED] = onFulfillment; | ||
subscribers[length + REJECTED] = onRejection; | ||
var subscribers = parent._subscribers; | ||
var length = subscribers.length; | ||
subscribers[length] = child; | ||
subscribers[length + FULFILLED] = onFulfillment; | ||
subscribers[length + REJECTED] = onRejection; | ||
} | ||
function publish(promise, settled) { | ||
var child, callback, subscribers = promise._subscribers, detail = promise._detail; | ||
if (config.instrument) { | ||
instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); | ||
} | ||
for (var i = 0; i < subscribers.length; i += 3) { | ||
child = subscribers[i]; | ||
callback = subscribers[i + settled]; | ||
invokeCallback(settled, child, callback, detail); | ||
} | ||
promise._subscribers = null; | ||
var child, callback, subscribers = promise._subscribers, detail = promise._detail; | ||
if (config.instrument) { | ||
instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); | ||
} | ||
for (var i = 0; i < subscribers.length; i += 3) { | ||
child = subscribers[i]; | ||
callback = subscribers[i + settled]; | ||
invokeCallback(settled, child, callback, detail); | ||
} | ||
promise._subscribers = null; | ||
} | ||
Promise.prototype = { | ||
/** | ||
@property constructor | ||
*/ | ||
constructor: Promise, | ||
_id: undefined, | ||
_guidKey: guidKey, | ||
_label: undefined, | ||
_state: undefined, | ||
_detail: undefined, | ||
_subscribers: undefined, | ||
_onerror: function (reason) { | ||
config.trigger('error', reason); | ||
}, | ||
/** | ||
The primary way of interacting with a promise is through its `then` method, | ||
which registers callbacks to receive either a promise's eventual value or the | ||
reason why the promise cannot be fulfilled. | ||
```js | ||
findUser().then(function(user){ | ||
// user is available | ||
}, function(reason){ | ||
// user is unavailable, and you are given the reason why | ||
}); | ||
``` | ||
Chaining | ||
-------- | ||
The return value of `then` is itself a promise. This second, "downstream" | ||
promise is resolved with the return value of the first promise's fulfillment | ||
or rejection handler, or rejected if the handler throws an exception. | ||
```js | ||
findUser().then(function (user) { | ||
return user.name; | ||
}, function (reason) { | ||
return "default name"; | ||
}).then(function (userName) { | ||
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it | ||
// will be `"default name"` | ||
}); | ||
findUser().then(function (user) { | ||
throw new Error("Found user, but still unhappy"); | ||
}, function (reason) { | ||
throw new Error("`findUser` rejected and we're unhappy"); | ||
}).then(function (value) { | ||
// never reached | ||
}, function (reason) { | ||
// if `findUser` fulfilled, `reason` will be "Found user, but still unhappy". | ||
// If `findUser` rejected, `reason` will be "`findUser` rejected and we're unhappy". | ||
}); | ||
``` | ||
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. | ||
```js | ||
findUser().then(function (user) { | ||
throw new PedagogicalException("Upstream error"); | ||
}).then(function (value) { | ||
// never reached | ||
}).then(function (value) { | ||
// never reached | ||
}, function (reason) { | ||
// The `PedgagocialException` is propagated all the way down to here | ||
}); | ||
``` | ||
Assimilation | ||
------------ | ||
Sometimes the value you want to propagate to a downstream promise can only be | ||
retrieved asynchronously. This can be achieved by returning a promise in the | ||
fulfillment or rejection handler. The downstream promise will then be pending | ||
until the returned promise is settled. This is called *assimilation*. | ||
```js | ||
findUser().then(function (user) { | ||
return findCommentsByAuthor(user); | ||
}).then(function (comments) { | ||
// The user's comments are now available | ||
}); | ||
``` | ||
If the assimliated promise rejects, then the downstream promise will also reject. | ||
```js | ||
findUser().then(function (user) { | ||
return findCommentsByAuthor(user); | ||
}).then(function (comments) { | ||
// If `findCommentsByAuthor` fulfills, we'll have the value here | ||
}, function (reason) { | ||
// If `findCommentsByAuthor` rejects, we'll have the reason here | ||
}); | ||
``` | ||
Simple Example | ||
-------------- | ||
Synchronous Example | ||
```javascript | ||
var result; | ||
try { | ||
result = findResult(); | ||
// success | ||
} catch(reason) { | ||
// failure | ||
} | ||
``` | ||
Errback Example | ||
```js | ||
findResult(function(result, err){ | ||
if (err) { | ||
// failure | ||
} else { | ||
// success | ||
constructor: Promise, | ||
_id: undefined, | ||
_guidKey: guidKey, | ||
_label: undefined, | ||
_state: undefined, | ||
_detail: undefined, | ||
_subscribers: undefined, | ||
_onerror: function (reason) { | ||
config.trigger('error', reason); | ||
}, | ||
then: function (onFulfillment, onRejection, label) { | ||
var promise = this; | ||
this._onerror = null; | ||
var thenPromise = new this.constructor(noop, label); | ||
if (this._state) { | ||
var callbacks = arguments; | ||
config.async(function invokePromiseCallback() { | ||
invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail); | ||
}); | ||
} else { | ||
subscribe(this, thenPromise, onFulfillment, onRejection); | ||
} | ||
if (config.instrument) { | ||
instrument('chained', promise, thenPromise); | ||
} | ||
return thenPromise; | ||
}, | ||
'catch': function (onRejection, label) { | ||
return this.then(null, onRejection, label); | ||
}, | ||
'finally': function (callback, label) { | ||
var constructor = this.constructor; | ||
return this.then(function (value) { | ||
return constructor.cast(callback()).then(function () { | ||
return value; | ||
}); | ||
}, function (reason) { | ||
return constructor.cast(callback()).then(function () { | ||
throw reason; | ||
}); | ||
}, label); | ||
} | ||
}); | ||
``` | ||
Promise Example; | ||
```javascript | ||
findResult().then(function(result){ | ||
// success | ||
}, function(reason){ | ||
// failure | ||
}); | ||
``` | ||
Advanced Example | ||
-------------- | ||
Synchronous Example | ||
```javascript | ||
var author, books; | ||
try { | ||
author = findAuthor(); | ||
books = findBooksByAuthor(author); | ||
// success | ||
} catch(reason) { | ||
// failure | ||
} | ||
``` | ||
Errback Example | ||
```js | ||
function foundBooks(books) { | ||
} | ||
function failure(reason) { | ||
} | ||
findAuthor(function(author, err){ | ||
if (err) { | ||
failure(err); | ||
// failure | ||
}; | ||
function invokeCallback(settled, promise, callback, detail) { | ||
var hasCallback = isFunction(callback), value, error, succeeded, failed; | ||
if (hasCallback) { | ||
try { | ||
value = callback(detail); | ||
succeeded = true; | ||
} catch (e) { | ||
failed = true; | ||
error = e; | ||
} | ||
} else { | ||
try { | ||
findBoooksByAuthor(author, function(books, err) { | ||
if (err) { | ||
failure(err); | ||
} else { | ||
try { | ||
foundBooks(books); | ||
} catch(reason) { | ||
failure(reason); | ||
} | ||
} | ||
}); | ||
} catch(error) { | ||
failure(err); | ||
} | ||
// success | ||
value = detail; | ||
succeeded = true; | ||
} | ||
}); | ||
``` | ||
Promise Example; | ||
```javascript | ||
findAuthor(). | ||
then(findBooksByAuthor). | ||
then(function(books){ | ||
// found books | ||
}).catch(function(reason){ | ||
// something went wrong | ||
}); | ||
``` | ||
@method then | ||
@param {Function} onFulfilled | ||
@param {Function} onRejected | ||
@param {String} label optional string for labeling the promise. | ||
Useful for tooling. | ||
@return {Promise} | ||
*/ | ||
then: function(onFulfillment, onRejection, label) { | ||
var promise = this; | ||
this._onerror = null; | ||
var thenPromise = new this.constructor(noop, label); | ||
if (this._state) { | ||
var callbacks = arguments; | ||
config.async(function invokePromiseCallback() { | ||
invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail); | ||
}); | ||
} else { | ||
subscribe(this, thenPromise, onFulfillment, onRejection); | ||
if (handleThenable(promise, value)) { | ||
return; | ||
} else if (hasCallback && succeeded) { | ||
resolve(promise, value); | ||
} else if (failed) { | ||
reject(promise, error); | ||
} else if (settled === FULFILLED) { | ||
resolve(promise, value); | ||
} else if (settled === REJECTED) { | ||
reject(promise, value); | ||
} | ||
if (config.instrument) { | ||
instrument('chained', promise, thenPromise); | ||
} | ||
return thenPromise; | ||
}, | ||
/** | ||
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same | ||
as the catch block of a try/catch statement. | ||
```js | ||
function findAuthor(){ | ||
throw new Error("couldn't find that author"); | ||
} | ||
// synchronous | ||
try { | ||
findAuthor(); | ||
} catch(reason) { | ||
// something went wrong | ||
} | ||
// async with promises | ||
findAuthor().catch(function(reason){ | ||
// something went wrong | ||
}); | ||
``` | ||
@method catch | ||
@param {Function} onRejection | ||
@param {String} label optional string for labeling the promise. | ||
Useful for tooling. | ||
@return {Promise} | ||
*/ | ||
'catch': function(onRejection, label) { | ||
return this.then(null, onRejection, label); | ||
}, | ||
/** | ||
`finally` will be invoked regardless of the promise's fate just as native | ||
try/catch/finally behaves | ||
Synchronous example: | ||
```js | ||
findAuthor() { | ||
if (Math.random() > 0.5) { | ||
throw new Error(); | ||
} | ||
return new Author(); | ||
} | ||
try { | ||
return findAuthor(); // succeed or fail | ||
} catch(error) { | ||
return findOtherAuther(); | ||
} finally { | ||
// always runs | ||
// doesn't affect the return value | ||
} | ||
``` | ||
Asynchronous example: | ||
```js | ||
findAuthor().catch(function(reason){ | ||
return findOtherAuther(); | ||
}).finally(function(){ | ||
// author was either found, or not | ||
}); | ||
``` | ||
@method finally | ||
@param {Function} callback | ||
@param {String} label optional string for labeling the promise. | ||
Useful for tooling. | ||
@return {Promise} | ||
*/ | ||
'finally': function(callback, label) { | ||
var constructor = this.constructor; | ||
return this.then(function(value) { | ||
return constructor.cast(callback()).then(function(){ | ||
return value; | ||
}); | ||
}, function(reason) { | ||
return constructor.cast(callback()).then(function(){ | ||
throw reason; | ||
}); | ||
}, label); | ||
} | ||
}; | ||
function invokeCallback(settled, promise, callback, detail) { | ||
var hasCallback = isFunction(callback), | ||
value, error, succeeded, failed; | ||
if (hasCallback) { | ||
try { | ||
value = callback(detail); | ||
succeeded = true; | ||
} catch(e) { | ||
failed = true; | ||
error = e; | ||
} | ||
} else { | ||
value = detail; | ||
succeeded = true; | ||
} | ||
if (handleThenable(promise, value)) { | ||
return; | ||
} else if (hasCallback && succeeded) { | ||
resolve(promise, value); | ||
} else if (failed) { | ||
reject(promise, error); | ||
} else if (settled === FULFILLED) { | ||
resolve(promise, value); | ||
} else if (settled === REJECTED) { | ||
reject(promise, value); | ||
} | ||
} | ||
function handleThenable(promise, value) { | ||
var then = null, | ||
resolved; | ||
try { | ||
if (promise === value) { | ||
throw new TypeError("A promises callback cannot return that same promise."); | ||
} | ||
if (objectOrFunction(value)) { | ||
then = value.then; | ||
if (isFunction(then)) { | ||
then.call(value, function(val) { | ||
if (resolved) { return true; } | ||
resolved = true; | ||
if (value !== val) { | ||
resolve(promise, val); | ||
} else { | ||
fulfill(promise, val); | ||
} | ||
}, function(val) { | ||
if (resolved) { return true; } | ||
resolved = true; | ||
reject(promise, val); | ||
}, 'derived from: ' + (promise._label || ' unknown promise')); | ||
var then = null, resolved; | ||
try { | ||
if (promise === value) { | ||
throw new TypeError('A promises callback cannot return that same promise.'); | ||
} | ||
if (objectOrFunction(value)) { | ||
then = value.then; | ||
if (isFunction(then)) { | ||
then.call(value, function (val) { | ||
if (resolved) { | ||
return true; | ||
} | ||
resolved = true; | ||
if (value !== val) { | ||
resolve(promise, val); | ||
} else { | ||
fulfill(promise, val); | ||
} | ||
}, function (val) { | ||
if (resolved) { | ||
return true; | ||
} | ||
resolved = true; | ||
reject(promise, val); | ||
}, 'Settle: ' + (promise._label || ' unknown promise')); | ||
return true; | ||
} | ||
} | ||
} catch (error) { | ||
if (resolved) { | ||
return true; | ||
} | ||
reject(promise, error); | ||
return true; | ||
} | ||
} | ||
} catch (error) { | ||
if (resolved) { return true; } | ||
reject(promise, error); | ||
return true; | ||
} | ||
return false; | ||
return false; | ||
} | ||
function resolve(promise, value) { | ||
if (promise === value) { | ||
fulfill(promise, value); | ||
} else if (!handleThenable(promise, value)) { | ||
fulfill(promise, value); | ||
} | ||
if (promise === value) { | ||
fulfill(promise, value); | ||
} else if (!handleThenable(promise, value)) { | ||
fulfill(promise, value); | ||
} | ||
} | ||
function fulfill(promise, value) { | ||
if (promise._state !== PENDING) { return; } | ||
promise._state = SEALED; | ||
promise._detail = value; | ||
config.async(publishFulfillment, promise); | ||
if (promise._state !== PENDING) { | ||
return; | ||
} | ||
promise._state = SEALED; | ||
promise._detail = value; | ||
config.async(publishFulfillment, promise); | ||
} | ||
function reject(promise, reason) { | ||
if (promise._state !== PENDING) { return; } | ||
promise._state = SEALED; | ||
promise._detail = reason; | ||
config.async(publishRejection, promise); | ||
if (promise._state !== PENDING) { | ||
return; | ||
} | ||
promise._state = SEALED; | ||
promise._detail = reason; | ||
config.async(publishRejection, promise); | ||
} | ||
function publishFulfillment(promise) { | ||
publish(promise, promise._state = FULFILLED); | ||
publish(promise, promise._state = FULFILLED); | ||
} | ||
function publishRejection(promise) { | ||
if (promise._onerror) { | ||
promise._onerror(promise._detail); | ||
} | ||
publish(promise, promise._state = REJECTED); | ||
if (promise._onerror) { | ||
promise._onerror(promise._detail); | ||
} | ||
publish(promise, promise._state = REJECTED); | ||
} |
@@ -1,7 +0,5 @@ | ||
"use strict"; | ||
var isArray = require("../utils").isArray; | ||
var isNonThenable = require("../utils").isNonThenable; | ||
'use strict'; | ||
var isArray = require('../utils').isArray; | ||
var isNonThenable = require('../utils').isNonThenable; | ||
/** | ||
`RSVP.Promise.all` accepts an array of promises, and returns a new promise which | ||
@@ -45,3 +43,3 @@ is fulfilled with an array of fulfillment values for the passed promises, or | ||
@method all | ||
@for RSVP.Promise | ||
@static | ||
@param {Array} entries array of promises | ||
@@ -52,48 +50,42 @@ @param {String} label optional string for labeling the promise. | ||
fulfilled, or rejected if any of them become rejected. | ||
@static | ||
*/ | ||
exports["default"] = function all(entries, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function(resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to all.'); | ||
} | ||
var remaining = entries.length; | ||
var results = new Array(remaining); | ||
var entry, pending = true; | ||
if (remaining === 0) { | ||
resolve(results); | ||
return; | ||
} | ||
function fulfillmentAt(index) { | ||
return function(value) { | ||
results[index] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
exports['default'] = function all(entries, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function (resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to all.'); | ||
} | ||
}; | ||
} | ||
function onRejection(reason) { | ||
remaining = 0; | ||
reject(reason); | ||
} | ||
for (var index = 0; index < entries.length; index++) { | ||
entry = entries[index]; | ||
if (isNonThenable(entry)) { | ||
results[index] = entry; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
var remaining = entries.length; | ||
var results = new Array(remaining); | ||
var entry, pending = true; | ||
if (remaining === 0) { | ||
resolve(results); | ||
return; | ||
} | ||
} else { | ||
Constructor.cast(entry).then(fulfillmentAt(index), onRejection); | ||
} | ||
} | ||
}, label); | ||
function fulfillmentAt(index) { | ||
return function (value) { | ||
results[index] = value; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
}; | ||
} | ||
function onRejection(reason) { | ||
remaining = 0; | ||
reject(reason); | ||
} | ||
for (var index = 0; index < entries.length; index++) { | ||
entry = entries[index]; | ||
if (isNonThenable(entry)) { | ||
results[index] = entry; | ||
if (--remaining === 0) { | ||
resolve(results); | ||
} | ||
} else { | ||
Constructor.resolve(entry).then(fulfillmentAt(index), onRejection); | ||
} | ||
} | ||
}, label); | ||
}; |
@@ -1,3 +0,4 @@ | ||
"use strict"; | ||
'use strict'; | ||
/** | ||
@deprecated | ||
@@ -63,3 +64,3 @@ `RSVP.Promise.cast` coerces its argument to a promise, or returns the | ||
@method cast | ||
@for RSVP.Promise | ||
@static | ||
@param {Object} object to be casted | ||
@@ -70,14 +71,11 @@ @param {String} label optional string for labeling the promise. | ||
*/ | ||
exports["default"] = function cast(object, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
if (object && typeof object === 'object' && object.constructor === Constructor) { | ||
return object; | ||
} | ||
return new Constructor(function(resolve) { | ||
resolve(object); | ||
}, label); | ||
exports['default'] = function cast(object, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
if (object && typeof object === 'object' && object.constructor === Constructor) { | ||
return object; | ||
} | ||
return new Constructor(function (resolve) { | ||
resolve(object); | ||
}, label); | ||
}; |
@@ -1,8 +0,6 @@ | ||
"use strict"; | ||
'use strict'; | ||
/* global toString */ | ||
var isArray = require("../utils").isArray; | ||
var isFunction = require("../utils").isFunction; | ||
var isNonThenable = require("../utils").isNonThenable; | ||
var isArray = require('../utils').isArray; | ||
var isFunction = require('../utils').isFunction; | ||
var isNonThenable = require('../utils').isNonThenable; | ||
/** | ||
@@ -53,3 +51,3 @@ `RSVP.Promise.race` returns a new promise which is settled in the same way as the | ||
RSVP.Promise.race([promise1, promise2]).then(function(result){ | ||
// Code here never runs because there are rejected promises! | ||
// Code here never runs | ||
}, function(reason){ | ||
@@ -68,3 +66,3 @@ // reason.message === "promise2" because promise 2 became rejected before | ||
@method race | ||
@for RSVP.Promise | ||
@static | ||
@param {Array} promises array of promises to observe | ||
@@ -76,27 +74,33 @@ @param {String} label optional string for describing the promise returned. | ||
*/ | ||
exports["default"] = function race(entries, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this, entry; | ||
return new Constructor(function(resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to race.'); | ||
} | ||
var pending = true; | ||
function onFulfillment(value) { if (pending) { pending = false; resolve(value); } } | ||
function onRejection(reason) { if (pending) { pending = false; reject(reason); } } | ||
for (var i = 0; i < entries.length; i++) { | ||
entry = entries[i]; | ||
if (isNonThenable(entry)) { | ||
pending = false; | ||
resolve(entry); | ||
return; | ||
} else { | ||
Constructor.cast(entry).then(onFulfillment, onRejection); | ||
} | ||
} | ||
}, label); | ||
exports['default'] = function race(entries, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this, entry; | ||
return new Constructor(function (resolve, reject) { | ||
if (!isArray(entries)) { | ||
throw new TypeError('You must pass an array to race.'); | ||
} | ||
var pending = true; | ||
function onFulfillment(value) { | ||
if (pending) { | ||
pending = false; | ||
resolve(value); | ||
} | ||
} | ||
function onRejection(reason) { | ||
if (pending) { | ||
pending = false; | ||
reject(reason); | ||
} | ||
} | ||
for (var i = 0; i < entries.length; i++) { | ||
entry = entries[i]; | ||
if (isNonThenable(entry)) { | ||
pending = false; | ||
resolve(entry); | ||
return; | ||
} else { | ||
Constructor.resolve(entry).then(onFulfillment, onRejection); | ||
} | ||
} | ||
}, label); | ||
}; |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
'use strict'; | ||
/** | ||
@@ -31,3 +31,3 @@ `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. | ||
@method reject | ||
@for RSVP.Promise | ||
@static | ||
@param {Any} reason value that the returned promise will be rejected with. | ||
@@ -38,9 +38,8 @@ @param {String} label optional string for identifying the returned promise. | ||
*/ | ||
exports["default"] = function reject(reason, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function (resolve, reject) { | ||
reject(reason); | ||
}, label); | ||
exports['default'] = function reject(reason, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function (resolve, reject$2) { | ||
reject$2(reason); | ||
}, label); | ||
}; |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
'use strict'; | ||
/** | ||
@@ -27,3 +27,3 @@ `RSVP.Promise.resolve` returns a promise that will become resolved with the | ||
@method resolve | ||
@for RSVP.Promise | ||
@static | ||
@param {Any} value value that the returned promise will be resolved with | ||
@@ -35,9 +35,11 @@ @param {String} label optional string for identifying the returned promise. | ||
*/ | ||
exports["default"] = function resolve(value, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function(resolve, reject) { | ||
resolve(value); | ||
}, label); | ||
exports['default'] = function resolve(object, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
if (object && typeof object === 'object' && object.constructor === Constructor) { | ||
return object; | ||
} | ||
return new Constructor(function (resolve$2) { | ||
resolve$2(object); | ||
}, label); | ||
}; |
@@ -1,6 +0,15 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.race`. | ||
exports["default"] = function race(array, label) { | ||
return Promise.race(array, label); | ||
@method race | ||
@static | ||
@for RSVP | ||
@param {Array} array Array of promises. | ||
@param {String} label An optional label. This is useful | ||
for tooling. | ||
*/ | ||
exports['default'] = function race(array, label) { | ||
return Promise.race(array, label); | ||
}; |
@@ -1,6 +0,16 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.reject`. | ||
exports["default"] = function reject(reason, label) { | ||
return Promise.reject(reason, label); | ||
@method reject | ||
@static | ||
@for RSVP | ||
@param {Any} reason value that the returned promise will be rejected with. | ||
@param {String} label optional string for identifying the returned promise. | ||
Useful for tooling. | ||
@return {Promise} a promise rejected with the given `reason`. | ||
*/ | ||
exports['default'] = function reject(reason, label) { | ||
return Promise.reject(reason, label); | ||
}; |
@@ -1,6 +0,17 @@ | ||
"use strict"; | ||
var Promise = require("./promise")["default"]; | ||
'use strict'; | ||
var Promise = require('./promise')['default']; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.resolve`. | ||
exports["default"] = function resolve(value, label) { | ||
return Promise.resolve(value, label); | ||
@method resolve | ||
@static | ||
@for RSVP | ||
@param {Any} value value that the returned promise will be resolved with | ||
@param {String} label optional string for identifying the returned promise. | ||
Useful for tooling. | ||
@return {Promise} a promise that will become fulfilled with the given | ||
`value` | ||
*/ | ||
exports['default'] = function resolve(value, label) { | ||
return Promise.resolve(value, label); | ||
}; |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
'use strict'; | ||
/** | ||
@@ -36,11 +36,13 @@ `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event | ||
@method rethrow | ||
@static | ||
@for RSVP | ||
@param {Error} reason reason the promise became rejected. | ||
@throws Error | ||
@static | ||
*/ | ||
exports["default"] = function rethrow(reason) { | ||
setTimeout(function() { | ||
exports['default'] = function rethrow(reason) { | ||
setTimeout(function () { | ||
throw reason; | ||
}); | ||
throw reason; | ||
}); | ||
throw reason; | ||
}; |
@@ -1,31 +0,37 @@ | ||
"use strict"; | ||
'use strict'; | ||
function objectOrFunction(x) { | ||
return typeof x === "function" || (typeof x === "object" && x !== null); | ||
return typeof x === 'function' || typeof x === 'object' && x !== null; | ||
} | ||
exports.objectOrFunction = objectOrFunction;function isFunction(x) { | ||
return typeof x === "function"; | ||
exports.objectOrFunction = objectOrFunction; | ||
function isFunction(x) { | ||
return typeof x === 'function'; | ||
} | ||
exports.isFunction = isFunction;function isNonThenable(x) { | ||
return !objectOrFunction(x); | ||
exports.isFunction = isFunction; | ||
function isNonThenable(x) { | ||
return !objectOrFunction(x); | ||
} | ||
exports.isNonThenable = isNonThenable;function isArray(x) { | ||
return Object.prototype.toString.call(x) === "[object Array]"; | ||
exports.isNonThenable = isNonThenable; | ||
var _isArray; | ||
if (!Array.isArray) { | ||
_isArray = function (x) { | ||
return Object.prototype.toString.call(x) === '[object Array]'; | ||
}; | ||
} else { | ||
_isArray = Array.isArray; | ||
} | ||
exports.isArray = isArray;// Date.now is not available in browsers < IE9 | ||
var isArray = _isArray; | ||
exports.isArray = isArray; | ||
// Date.now is not available in browsers < IE9 | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility | ||
var now = Date.now || function() { return new Date().getTime(); }; | ||
var now = Date.now || function () { | ||
return new Date().getTime(); | ||
}; | ||
exports.now = now; | ||
var keysOf = Object.keys || function(object) { | ||
var result = []; | ||
for (var prop in object) { | ||
result.push(prop); | ||
} | ||
return result; | ||
}; | ||
var keysOf = Object.keys || function (object) { | ||
var result = []; | ||
for (var prop in object) { | ||
result.push(prop); | ||
} | ||
return result; | ||
}; | ||
exports.keysOf = keysOf; |
@@ -8,2 +8,3 @@ import Promise from "./rsvp/promise"; | ||
import hash from "./rsvp/hash"; | ||
import hashSettled from "./rsvp/hash_settled"; | ||
import rethrow from "./rsvp/rethrow"; | ||
@@ -43,2 +44,2 @@ import defer from "./rsvp/defer"; | ||
export { Promise, EventTarget, all, allSettled, race, hash, rethrow, defer, denodeify, configure, on, off, resolve, reject, async, map, filter }; | ||
export { Promise, EventTarget, all, allSettled, race, hash, hashSettled, rethrow, defer, denodeify, configure, on, off, resolve, reject, async, map, filter }; |
@@ -46,5 +46,6 @@ import Promise from "./promise"; | ||
@method @allSettled | ||
@method allSettled | ||
@static | ||
@for RSVP | ||
@param {Array} promises; | ||
@param {Array} promises | ||
@param {String} label - optional string that describes the promise. | ||
@@ -97,3 +98,3 @@ Useful for tooling. | ||
} else { | ||
Promise.cast(entry).then(fulfilledResolver(index), rejectedResolver(index)); | ||
Promise.resolve(entry).then(fulfilledResolver(index), rejectedResolver(index)); | ||
} | ||
@@ -100,0 +101,0 @@ } |
import Promise from "./promise"; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.all`. | ||
@method all | ||
@static | ||
@for RSVP | ||
@param {Array} array Array of promises. | ||
@param {String} label An optional label. This is useful | ||
for tooling. | ||
*/ | ||
export default function all(array, label) { | ||
return Promise.all(array, label); | ||
}; |
@@ -29,2 +29,3 @@ import Promise from "./promise"; | ||
@method defer | ||
@static | ||
@for RSVP | ||
@@ -31,0 +32,0 @@ @param {String} label optional string for labeling the promise. |
@@ -20,4 +20,3 @@ var indexOf = function(callbacks, callback) { | ||
/** | ||
//@module RSVP | ||
//@class EventTarget | ||
@class RSVP.EventTarget | ||
*/ | ||
@@ -64,4 +63,5 @@ export default { | ||
@method mixin | ||
@for RSVP.EventTarget | ||
@private | ||
@param {Object} object object to extend with EventTarget methods | ||
@private | ||
*/ | ||
@@ -88,5 +88,6 @@ mixin: function(object) { | ||
@method on | ||
@for RSVP.EventTarget | ||
@private | ||
@param {String} eventName name of the event to listen for | ||
@param {Function} callback function to be called when the event is triggered. | ||
@private | ||
*/ | ||
@@ -138,2 +139,4 @@ on: function(eventName, callback) { | ||
@method off | ||
@for RSVP.EventTarget | ||
@private | ||
@param {String} eventName event to stop listening to | ||
@@ -144,4 +147,2 @@ @param {Function} callback optional argument. If given, only the function | ||
queue. | ||
@private | ||
*/ | ||
@@ -187,6 +188,7 @@ off: function(eventName, callback) { | ||
@method trigger | ||
@for RSVP.EventTarget | ||
@private | ||
@param {String} eventName name of the event to be triggered | ||
@param {Any} options optional value to be passed to any event handlers for | ||
the given `eventName` | ||
@private | ||
*/ | ||
@@ -193,0 +195,0 @@ trigger: function(eventName, options) { |
@@ -1,4 +0,3 @@ | ||
import all from "./all"; | ||
import map from "./map"; | ||
import { isFunction, isArray } from "./utils"; | ||
import Promise from "./promise"; | ||
import { isFunction } from "./utils"; | ||
@@ -79,2 +78,3 @@ /** | ||
@method filter | ||
@static | ||
@for RSVP | ||
@@ -88,25 +88,27 @@ @param {Array} promises | ||
*/ | ||
function filter(promises, filterFn, label) { | ||
return all(promises, label).then(function(values){ | ||
if (!isArray(promises)) { | ||
throw new TypeError('You must pass an array to filter.'); | ||
export default function filter(promises, filterFn, label) { | ||
return Promise.all(promises, label).then(function(values) { | ||
if (!isFunction(filterFn)) { | ||
throw new TypeError("You must pass a function as filter's second argument."); | ||
} | ||
if (!isFunction(filterFn)){ | ||
throw new TypeError("You must pass a function to filter's second argument."); | ||
var length = values.length; | ||
var filtered = new Array(length); | ||
for (var i = 0; i < length; i++) { | ||
filtered[i] = filterFn(values[i]); | ||
} | ||
return map(promises, filterFn, label).then(function(filterResults){ | ||
var i, | ||
valuesLen = values.length, | ||
filtered = []; | ||
return Promise.all(filtered, label).then(function(filtered) { | ||
var results = []; | ||
for (i = 0; i < valuesLen; i++){ | ||
if(filterResults[i]) filtered.push(values[i]); | ||
} | ||
return filtered; | ||
for (var i = 0; i < length; i++) { | ||
if (filtered[i] === true) { | ||
results.push(values[i]); | ||
} | ||
} | ||
return results; | ||
}); | ||
}); | ||
} | ||
export default filter; |
@@ -84,5 +84,6 @@ import Promise from "./promise"; | ||
@method hash | ||
@static | ||
@for RSVP | ||
@param {Object} promises | ||
@param {String} label - optional string that describes the promise. | ||
@param {String} label optional string that describes the promise. | ||
Useful for tooling. | ||
@@ -128,3 +129,3 @@ @return {Promise} promise that is fulfilled when all properties of `promises` | ||
} else { | ||
Promise.cast(entry).then(fulfilledTo(property), onRejection); | ||
Promise.resolve(entry).then(fulfilledTo(property), onRejection); | ||
} | ||
@@ -131,0 +132,0 @@ } |
import Promise from "./promise"; | ||
import all from "./all"; | ||
import { isArray, isFunction } from "./utils"; | ||
/** | ||
`RSVP.map` is similar to JavaScript's native `map` method, except that it | ||
@@ -73,2 +71,3 @@ waits for all promises to become fulfilled before running the `mapFn` on | ||
@method map | ||
@static | ||
@for RSVP | ||
@@ -82,24 +81,19 @@ @param {Array} promises | ||
The promise will be rejected if any of the given `promises` become rejected. | ||
@static | ||
*/ | ||
export default function map(promises, mapFn, label) { | ||
return all(promises, label).then(function(results){ | ||
if (!isArray(promises)) { | ||
throw new TypeError('You must pass an array to map.'); | ||
return Promise.all(promises, label).then(function(values) { | ||
if (!isFunction(mapFn)) { | ||
throw new TypeError("You must pass a function as map's second argument."); | ||
} | ||
if (!isFunction(mapFn)){ | ||
throw new TypeError("You must pass a function to map's second argument."); | ||
} | ||
var length = values.length; | ||
var results = new Array(length); | ||
var resultLen = results.length, | ||
mappedResults = [], | ||
i; | ||
for (i = 0; i < resultLen; i++){ | ||
mappedResults.push(mapFn(results[i])); | ||
for (var i = 0; i < length; i++) { | ||
results[i] = mapFn(values[i]); | ||
} | ||
return all(mappedResults, label); | ||
return Promise.all(results, label); | ||
}); | ||
}; | ||
} |
@@ -0,17 +1,6 @@ | ||
/* global $a_slice */ | ||
import Promise from "./promise"; | ||
import { isArray } from "./utils"; | ||
var slice = Array.prototype.slice; | ||
function makeNodeCallbackFor(resolve, reject) { | ||
return function (error, value) { | ||
if (error) { | ||
reject(error); | ||
} else if (arguments.length > 2) { | ||
resolve(slice.call(arguments, 1)); | ||
} else { | ||
resolve(value); | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -36,3 +25,2 @@ `RSVP.denodeify` takes a "node-style" function and returns a function that | ||
var fs = require('fs'); | ||
var readFile = RSVP.denodeify(fs.readFile); | ||
@@ -43,2 +31,58 @@ | ||
If the node function has multiple success parameters, then `denodeify` | ||
just returns the first one: | ||
```javascript | ||
var request = RSVP.denodeify(require('request')); | ||
request('http://example.com').then(function(res) { | ||
// ... | ||
}); | ||
``` | ||
However, if you need all success parameters, setting `denodeify`'s | ||
second parameter to `true` causes it to return all success parameters | ||
as an array: | ||
```javascript | ||
var request = RSVP.denodeify(require('request'), true); | ||
request('http://example.com').then(function(result) { | ||
// result[0] -> res | ||
// result[1] -> body | ||
}); | ||
``` | ||
Or if you pass it an array with names it returns the parameters as a hash: | ||
```javascript | ||
var request = RSVP.denodeify(require('request'), ['res', 'body']); | ||
request('http://example.com').then(function(result) { | ||
// result.res | ||
// result.body | ||
}); | ||
``` | ||
Sometimes you need to retain the `this`: | ||
```javascript | ||
var app = require('express')(); | ||
var render = RSVP.denodeify(app.render.bind(app)); | ||
``` | ||
The denodified function inherits from the original function. It works in all | ||
environments, except IE 10 and below. Consequently all properties of the original | ||
function are available to you. However, any properties you change on the | ||
denodeified function won't be changed on the original function. Example: | ||
```javascript | ||
var request = RSVP.denodeify(require('request')), | ||
cookieJar = request.jar(); // <- Inheritance is used here | ||
request('http://example.com', {jar: cookieJar}).then(function(res) { | ||
// cookieJar.cookies holds now the cookies returned by example.com | ||
}); | ||
``` | ||
Using `denodeify` makes it easier to compose asynchronous operations instead | ||
@@ -49,11 +93,8 @@ of using callbacks. For example, instead of: | ||
var fs = require('fs'); | ||
var log = require('some-async-logger'); | ||
fs.readFile('myfile.txt', function(err, data){ | ||
if (err) return handleError(err); | ||
if (err) { ... } // Handle error | ||
fs.writeFile('myfile2.txt', data, function(err){ | ||
if (err) throw err; | ||
log('success', function(err) { | ||
if (err) throw err; | ||
}); | ||
if (err) { ... } // Handle error | ||
console.log('done') | ||
}); | ||
@@ -63,10 +104,8 @@ }); | ||
You can chain the operations together using `then` from the returned promise: | ||
you can chain the operations together using `then` from the returned promise: | ||
```javascript | ||
var fs = require('fs'); | ||
var denodeify = RSVP.denodeify; | ||
var readFile = denodeify(fs.readFile); | ||
var writeFile = denodeify(fs.writeFile); | ||
var log = denodeify(require('some-async-logger')); | ||
var readFile = RSVP.denodeify(fs.readFile); | ||
var writeFile = RSVP.denodeify(fs.writeFile); | ||
@@ -76,7 +115,5 @@ readFile('myfile.txt').then(function(data){ | ||
}).then(function(){ | ||
return log('SUCCESS'); | ||
}).then(function(){ | ||
// success handler | ||
}, function(reason){ | ||
// rejection handler | ||
console.log('done') | ||
}).catch(function(error){ | ||
// Handle error | ||
}); | ||
@@ -86,2 +123,3 @@ ``` | ||
@method denodeify | ||
@static | ||
@for RSVP | ||
@@ -92,23 +130,73 @@ @param {Function} nodeFunc a "node-style" function that takes a callback as | ||
operation as its second argument ("function(err, value){ }"). | ||
@param {Any} binding optional argument for binding the "this" value when | ||
calling the `nodeFunc` function. | ||
@param {Boolean|Array} argumentNames An optional paramter that if set | ||
to `true` causes the promise to fulfill with the callback's success arguments | ||
as an array. This is useful if the node function has multiple success | ||
paramters. If you set this paramter to an array with names, the promise will | ||
fulfill with a hash with these names as keys and the success parameters as | ||
values. | ||
@return {Function} a function that wraps `nodeFunc` to return an | ||
`RSVP.Promise` | ||
@static | ||
*/ | ||
export default function denodeify(nodeFunc, binding) { | ||
return function() { | ||
var nodeArgs = slice.call(arguments), resolve, reject; | ||
var thisArg = this || binding; | ||
export default function denodeify(nodeFunc, argumentNames) { | ||
var asArray = argumentNames === true; | ||
var asHash = isArray(argumentNames); | ||
return new Promise(function(resolve, reject) { | ||
Promise.all(nodeArgs).then(function(nodeArgs) { | ||
try { | ||
nodeArgs.push(makeNodeCallbackFor(resolve, reject)); | ||
nodeFunc.apply(thisArg, nodeArgs); | ||
} catch(e) { | ||
reject(e); | ||
function denodeifiedFunction() { | ||
var nodeArgs; | ||
$a_slice(nodeArgs, arguments); | ||
var thisArg; | ||
if (!asArray && !asHash && argumentNames) { | ||
console.warn('Deprecation: RSVP.denodeify() doesn\'t allow setting the ' + | ||
'"this" binding anymore. Use yourFunction.bind(yourThis) instead.'); | ||
thisArg = argumentNames; | ||
} else { | ||
thisArg = this; | ||
} | ||
return Promise.all(nodeArgs).then(function(nodeArgs) { | ||
return new Promise(resolver); | ||
// sweet.js has a bug, this resolver can't defined in the constructor | ||
// or the $a_slice macro doesn't work | ||
function resolver(resolve, reject) { | ||
function callback() { | ||
var args; | ||
$a_slice(args, arguments); | ||
var error = args[0]; | ||
var value = args[1]; | ||
if (error) { | ||
reject(error); | ||
} else if (asArray) { | ||
resolve(args.slice(1)); | ||
} else if (asHash) { | ||
var obj = {}; | ||
var successArguments = args.slice(1); | ||
var name; | ||
var i; | ||
for (i = 0; i < argumentNames.length; i++) { | ||
name = argumentNames[i]; | ||
obj[name] = successArguments[i]; | ||
} | ||
resolve(obj); | ||
} else { | ||
resolve(value); | ||
} | ||
} | ||
}); | ||
nodeArgs.push(callback); | ||
nodeFunc.apply(thisArg, nodeArgs); | ||
} | ||
}); | ||
}; | ||
denodeifiedFunction.__proto__ = nodeFunc; | ||
return denodeifiedFunction; | ||
}; |
@@ -20,3 +20,2 @@ import { config } from "./config"; | ||
/** | ||
Promise objects represent the eventual result of an asynchronous operation. The | ||
@@ -39,3 +38,13 @@ primary way of interacting with a promise is through its `then` method, which | ||
Promises that are fulfilled have a fulfillment value and are in the fulfilled | ||
state. Promises that are rejected have a rejection reason and are in the | ||
rejected state. A fulfillment value is never a thenable. | ||
Promises can also be said to *resolve* a value. If this value is also a | ||
promise, then the original promise's settled state will match the value's | ||
settled state. So a promise that *resolves* a promise that rejects will | ||
itself reject, and a promise that *resolves* a promise that fulfills will | ||
itself fulfill. | ||
Basic Usage: | ||
@@ -110,3 +119,3 @@ ------------ | ||
@class Promise | ||
@class RSVP.Promise | ||
@param {function} | ||
@@ -193,5 +202,2 @@ @param {String} label optional string for labeling the promise. | ||
Promise.prototype = { | ||
/** | ||
@property constructor | ||
*/ | ||
constructor: Promise, | ||
@@ -212,3 +218,2 @@ | ||
/** | ||
The primary way of interacting with a promise is through its `then` method, | ||
@@ -573,3 +578,3 @@ which registers callbacks to receive either a promise's eventual value or the | ||
reject(promise, val); | ||
}, 'derived from: ' + (promise._label || ' unknown promise')); | ||
}, 'Settle: ' + (promise._label || ' unknown promise')); | ||
@@ -576,0 +581,0 @@ return true; |
import { isArray, isNonThenable } from "../utils"; | ||
/** | ||
`RSVP.Promise.all` accepts an array of promises, and returns a new promise which | ||
@@ -43,3 +42,3 @@ is fulfilled with an array of fulfillment values for the passed promises, or | ||
@method all | ||
@for RSVP.Promise | ||
@static | ||
@param {Array} entries array of promises | ||
@@ -50,2 +49,3 @@ @param {String} label optional string for labeling the promise. | ||
fulfilled, or rejected if any of them become rejected. | ||
@static | ||
*/ | ||
@@ -93,3 +93,3 @@ export default function all(entries, label) { | ||
} else { | ||
Constructor.cast(entry).then(fulfillmentAt(index), onRejection); | ||
Constructor.resolve(entry).then(fulfillmentAt(index), onRejection); | ||
} | ||
@@ -96,0 +96,0 @@ } |
/** | ||
@deprecated | ||
@@ -62,3 +63,3 @@ `RSVP.Promise.cast` coerces its argument to a promise, or returns the | ||
@method cast | ||
@for RSVP.Promise | ||
@static | ||
@param {Object} object to be casted | ||
@@ -69,3 +70,2 @@ @param {String} label optional string for labeling the promise. | ||
*/ | ||
export default function cast(object, label) { | ||
@@ -72,0 +72,0 @@ /*jshint validthis:true */ |
@@ -50,3 +50,3 @@ /* global toString */ | ||
RSVP.Promise.race([promise1, promise2]).then(function(result){ | ||
// Code here never runs because there are rejected promises! | ||
// Code here never runs | ||
}, function(reason){ | ||
@@ -65,3 +65,3 @@ // reason.message === "promise2" because promise 2 became rejected before | ||
@method race | ||
@for RSVP.Promise | ||
@static | ||
@param {Array} promises array of promises to observe | ||
@@ -94,3 +94,3 @@ @param {String} label optional string for describing the promise returned. | ||
} else { | ||
Constructor.cast(entry).then(onFulfillment, onRejection); | ||
Constructor.resolve(entry).then(onFulfillment, onRejection); | ||
} | ||
@@ -97,0 +97,0 @@ } |
@@ -30,3 +30,3 @@ /** | ||
@method reject | ||
@for RSVP.Promise | ||
@static | ||
@param {Any} reason value that the returned promise will be rejected with. | ||
@@ -33,0 +33,0 @@ @param {String} label optional string for identifying the returned promise. |
@@ -26,3 +26,3 @@ /** | ||
@method resolve | ||
@for RSVP.Promise | ||
@static | ||
@param {Any} value value that the returned promise will be resolved with | ||
@@ -34,9 +34,13 @@ @param {String} label optional string for identifying the returned promise. | ||
*/ | ||
export default function resolve(value, label) { | ||
export default function resolve(object, label) { | ||
/*jshint validthis:true */ | ||
var Constructor = this; | ||
return new Constructor(function(resolve, reject) { | ||
resolve(value); | ||
if (object && typeof object === 'object' && object.constructor === Constructor) { | ||
return object; | ||
} | ||
return new Constructor(function(resolve) { | ||
resolve(object); | ||
}, label); | ||
}; |
import Promise from "./promise"; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.race`. | ||
@method race | ||
@static | ||
@for RSVP | ||
@param {Array} array Array of promises. | ||
@param {String} label An optional label. This is useful | ||
for tooling. | ||
*/ | ||
export default function race(array, label) { | ||
return Promise.race(array, label); | ||
}; |
import Promise from "./promise"; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.reject`. | ||
@method reject | ||
@static | ||
@for RSVP | ||
@param {Any} reason value that the returned promise will be rejected with. | ||
@param {String} label optional string for identifying the returned promise. | ||
Useful for tooling. | ||
@return {Promise} a promise rejected with the given `reason`. | ||
*/ | ||
export default function reject(reason, label) { | ||
return Promise.reject(reason, label); | ||
}; |
import Promise from "./promise"; | ||
/** | ||
This is a convenient alias for `RSVP.Promise.resolve`. | ||
@method resolve | ||
@static | ||
@for RSVP | ||
@param {Any} value value that the returned promise will be resolved with | ||
@param {String} label optional string for identifying the returned promise. | ||
Useful for tooling. | ||
@return {Promise} a promise that will become fulfilled with the given | ||
`value` | ||
*/ | ||
export default function resolve(value, label) { | ||
return Promise.resolve(value, label); | ||
}; |
@@ -35,5 +35,7 @@ /** | ||
@method rethrow | ||
@static | ||
@for RSVP | ||
@param {Error} reason reason the promise became rejected. | ||
@throws Error | ||
@static | ||
*/ | ||
@@ -40,0 +42,0 @@ export default function rethrow(reason) { |
@@ -13,6 +13,13 @@ export function objectOrFunction(x) { | ||
export function isArray(x) { | ||
return Object.prototype.toString.call(x) === "[object Array]"; | ||
var _isArray; | ||
if (!Array.isArray) { | ||
_isArray = function (x) { | ||
return Object.prototype.toString.call(x) === "[object Array]"; | ||
}; | ||
} else { | ||
_isArray = Array.isArray; | ||
} | ||
export var isArray = _isArray; | ||
// Date.now is not available in browsers < IE9 | ||
@@ -19,0 +26,0 @@ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility |
{ | ||
"name": "rsvp", | ||
"namespace": "RSVP", | ||
"version": "3.0.3", | ||
"version": "3.0.4", | ||
"description": "A lightweight library that provides tools for organizing asynchronous code", | ||
@@ -25,5 +25,4 @@ "main": "dist/commonjs/main.js", | ||
"grunt-s3": "~0.2.0-alpha.2", | ||
"jshint": "~0.9", | ||
"jshint": "~0.9.1", | ||
"load-grunt-config": "~0.5.0", | ||
"load-grunt-tasks": "~0.2.0", | ||
"mocha-phantomjs": "~3.1.6", | ||
@@ -33,3 +32,4 @@ "promises-aplus-tests": "git://github.com/stefanpenner/promises-tests.git", | ||
"grunt-contrib-yuidoc": "~0.5.0", | ||
"grunt-release-it": "0.0.3" | ||
"grunt-release-it": "0.0.3", | ||
"grunt-sweet.js": "~0.1.4" | ||
}, | ||
@@ -43,4 +43,4 @@ "scripts": { | ||
"type": "git", | ||
"url": "git://github.com/tildeio/rsvp.js.git", | ||
"dist": "git@github.com:components/rsvp.git" | ||
"url": "https://github.com/tildeio/rsvp.js.git", | ||
"dist": "git@github.com:components/rsvp.js.git" | ||
}, | ||
@@ -52,7 +52,6 @@ "bugs": { | ||
"promises", | ||
"futures", | ||
"events" | ||
"futures" | ||
], | ||
"author": "Tilde, Inc.", | ||
"author": "Tilde, Inc. & Stefan Penner", | ||
"license": "MIT" | ||
} |
126
README.md
@@ -5,4 +5,3 @@ # RSVP.js [![Build Status](https://secure.travis-ci.org/tildeio/rsvp.js.png?branch=master)](http://travis-ci.org/tildeio/rsvp.js) | ||
Specifically, it is a tiny implementation of Promises/A+ and a | ||
mixin for turning objects into event targets. | ||
Specifically, it is a tiny implementation of Promises/A+. | ||
@@ -43,3 +42,5 @@ It works in node and the browser. | ||
```javascript | ||
var promise = new RSVP.Promise(function(resolve, reject){ | ||
var RSVP = require('rsvp'); | ||
var promise = new RSVP.Promise(function(resolve, reject) { | ||
// succeed | ||
@@ -129,3 +130,3 @@ resolve(value); | ||
}).then(null, function(error) { | ||
}).catch(function(error) { | ||
// since no rejection handler was passed to the | ||
@@ -145,3 +146,3 @@ // first `.then`, the error propagates. | ||
// proceed with access to posts and comments | ||
}).then(null, function(error) { | ||
}).catch(function(error) { | ||
// handle errors in either of the two requests | ||
@@ -174,7 +175,10 @@ }); | ||
```javascript | ||
RSVP.on('error', function(event) { | ||
console.assert(false, event.detail); | ||
RSVP.on('error', function(reason) { | ||
console.assert(false, reason); | ||
}); | ||
``` | ||
**NOTE:** promises do allow for errors to be handled asynchronously, so | ||
this callback may result in false positives. | ||
**NOTE:** Usage of `RSVP.configure('onerror', yourCustomFunction);` is | ||
@@ -192,11 +196,10 @@ deprecated in favor of using `RSVP.on`. | ||
```javascript | ||
var postIds = [2, 3, 5, 7, 11, 13]; | ||
var promises = []; | ||
var promises = [2, 3, 5, 7, 11, 13].map(function(id){ | ||
return getJSON("/post/" + id + ".json"); | ||
}); | ||
for(var i = 0; i < postIds.length; i++) { | ||
promises.push(getJSON("/post/" + postIds[i] + ".json")); | ||
} | ||
RSVP.all(promises).then(function(posts) { | ||
// posts contains an array of results for the given promises | ||
// posts contains an array of results for the given promises | ||
}).catch(function(reason){ | ||
// if any of the promises fails. | ||
}); | ||
@@ -230,11 +233,41 @@ ``` | ||
## All settled and hash settled | ||
Sometimes you want to work with several promises at once, but instead of | ||
rejecting immediately if any promise is rejected, as with `all()` or `hash()`, | ||
you want to be able to inspect the results of all your promises, whether | ||
they fulfill or reject. For this purpose, you can use `allSettled()` and | ||
`hashSettled()`. These work exactly like `all()` and `hash()`, except that | ||
they fulfill with an array or hash (respectively) of the constituent promises' | ||
result states. Each state object will either indicate fulfillment or | ||
rejection, and provide the corresponding value or reason. The states will take | ||
one of the following formats: | ||
```javascript | ||
{ state: 'fulfilled', value: value } | ||
or | ||
{ state: 'rejected', reason: reason } | ||
``` | ||
## Deferred | ||
RSVP also has a RSVP.defer() method that returns a deferred object of the form | ||
`{ promise, resolve(x), reject(r) }`. This creates a deferred object without | ||
specifying how it will be resolved. However, the `RSVP.Promise` constructor is | ||
generally a better and less error-prone choice; we recommend using it in | ||
preference to `RSVP.defer()`. | ||
> The `RSVP.Promise` constructor is generally a better, less error-prone choice | ||
> than `RSVP.defer()`. Promises are recommended unless the specific | ||
> properties of deferred are needed. | ||
Sometimes one need to create a deferred object, without immediately specifying | ||
how it will be resolved. These deferred objects are essentially a wrapper around | ||
a promise, whilst providing late access to the `resolve()` and `reject()` methods. | ||
A deferred object has this form: `{ promise, resolve(x), reject(r) }`. | ||
```javascript | ||
var deferred = RSVP.defer(); | ||
// ... | ||
deferred.promise // access the promise | ||
// ... | ||
deferred.resolve(); | ||
``` | ||
## TaskJS | ||
@@ -252,3 +285,3 @@ | ||
// proceed with access to posts and comments | ||
}).then(null, function(error) { | ||
}).catch(function(reason) { | ||
// handle errors in either of the two requests | ||
@@ -283,53 +316,2 @@ }); | ||
## Event Target | ||
RSVP also provides a mixin that you can use to convert any object into | ||
an event target. The promises implementation uses `RSVP.EventTarget`, so | ||
`RSVP` exposes it for your own use. | ||
### Basic Usage | ||
The basic usage of `RSVP.EventTarget` is to mix it into an object, then | ||
use `on` and `trigger` to register listeners and trigger them. | ||
```javascript | ||
var object = {}; | ||
RSVP.EventTarget.mixin(object); | ||
object.on("finished", function(event) { | ||
// handle event | ||
}); | ||
object.trigger("finished", { detail: value }); | ||
``` | ||
### Prototypes | ||
You can mix `RSVP.EventTarget` into a prototype and it will work as | ||
expected. | ||
```javascript | ||
var Person = function() {}; | ||
RSVP.EventTarget.mixin(Person.prototype); | ||
var yehuda = new Person(); | ||
var tom = new Person(); | ||
yehuda.on("poke", function(event) { | ||
console.log("Yehuda says OW"); | ||
}); | ||
tom.on("poke", function(event) { | ||
console.log("Tom says OW"); | ||
}); | ||
yehuda.trigger("poke"); | ||
tom.trigger("poke"); | ||
``` | ||
The example will work as expected. If you mix `RSVP.EventTarget` into a | ||
constructor's prototype, each instance of that constructor will get its | ||
own callbacks. | ||
## Instrumentation | ||
@@ -359,4 +341,2 @@ | ||
This package uses the [grunt-microlib](https://github.com/thomasboyt/grunt-microlib) package for building. | ||
Custom tasks: | ||
@@ -363,0 +343,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
270994
56
7234
338