promised-utils.js | |
---|---|
'use strict' | |
Module exports set of of utility functions that are useful for working with promises. | var Q = require('q'), when = Q.when, defer = Q.defer, Get = Q.get, Set = Q.set, Post = Q.post
, _slice = Array.prototype.slice
, _forEach = Array.prototype.forEach |
allFunction takes array of promises and gives a new promise in return which will be fulfilled with an array of resolved promises that where passed. If any of the passed promises will get rejected, rejection will be forwarded to a returned promise. | /**
* Creates promise for array of the promises that is resolved with an array
* of the promise resolutions.
* @param {Promise[]} promises
* Array of promises to create promise for.
*/
function all(promises) {
var l = promises.length
, values = [] |
If empty array is passed to the function it is returned immediately. | if (0 == l) return values
var deferred = defer() |
Listeners are set for all the promises that where passed. | _forEach.call(promises, function(promise, index) {
when
( promise
, function resolved(value) { |
Resolved promises are stored in the array in the same exact order as they where passed to the function. | values[index] = value |
If all the observed promises are resolved resulting promise is resolved with an array of resolved promises. | if (0 === --l) deferred.resolve(values)
} |
If for some reason one of the promises is rejected, resulting promise is rejected with a same reason. | , function rejected(reason) { deferred.reject(reason) }
)
})
return deferred.promise
} |
Example: | exports.all = all |
PromisedFunction takes an object or a function as it's first argument. If first
argument is an object (or a promise that will be fulfilled to an object)
promise with extended API is returned. Extended promises come with following
methods: | /**
* @param {Function} callee
* @returns {Promise}
*/
function Promised(callee, sync) { |
If first argument is an object then wrapping it to a promise with an extended API. | if ('object' == typeof callee) return Object.create(when(callee), DPromised) |
Passed function is wrapped into another, so called promised function, that is returned as a result. | return function promised() { |
Returned function always returns a new promise when called. | var deferred = defer()
, reject = Reject(deferred, callee) |
It also assumes that all of the arguments passed to it represent promises. | , possiblyPromises = _slice.call(arguments, 0) |
In addition | possiblyPromises.unshift(this) |
When all the possible promises are resolved, wrapped function is called | when
( all(possiblyPromises) |
It is called with resolved promises as an arguments. | , function possiblePromisesResolved(params) {
try { |
If wrapped function was not identified as synchronous one additional argument, callback function is passed to it. | if (!sync) params.push(Callback(deferred)) |
Resolved | var value = callee.call.apply(callee, params) |
If value returned by wrapped function was different from
| if (sync || undefined !== value) deferred.resolve(value)
} catch(error) { |
If exception is thrown by wrapper function returned promise is rejected with it. | reject(error)
}
} |
If for some reason one of the promises gets rejected, returned promise will be rejected with same reason, but with additional details. | , reject
)
return deferred.promise
}
} |
Example: | exports.Promised = Promised |
Promised.asyncAt the moment functions wrapped by | Promised.async = Promised |
Promised.syncAs it was mentioned above | Promised.sync = function syncPromised(callee) {
return Promised(callee, true)
} |
Example: | |
RejectFunction takes deferred promise and function performing operation that may throw an exception that should result in rejection of promise. | function Reject(deferred, callee) { |
Callback function is returned as a result value. | return function reject(reason) { |
If callback is called wrapped promise is rejected with: | deferred.reject( |
| { at: callee.name |
| , cause: reason |
| , stack: new Error(callee.name).stack
})
}
} |
CallbackFunction takes deferred promise and returns node.js style callback function. | /**
* @param {Deferred}
* @returns {Function}
*/
function Callback(deferred) {
return function callback(error, value) { |
If returned callback is called with first non-falsy argument, wrapped promise is rejected with it. | if (error) deferred.reject(error) |
Otherwise promise is resolved with a value of a second argument. | else deferred.resolve(value)
}
}
exports.Callback = Callback |
Example:
Promised print function, just an utility to log promise values when they are resolved. | exports.print = Promised.sync(console.log.bind(console)) |
Extensions added to a promises returned by | var DPromised =
{ get: { value: function get(path) {
return Object.create(String(path).split('.').reduce(Get, this), DPromised)
}}
, set: { value: function set(path, value) {
path = String(path).split('.')
var name = path.pop()
return Object.create(Q.put(path.reduce(Get, this), name, value))
}}
, invoke: { value: function invoke(path, params) {
path = String(path).split('.')
var name = path.pop()
, target = path.reduce(Get, this)
return params ? Object.create(when(all(params), function onParams(params) {
return Post(target, name, params)
}, DPromised)) : Object.create(Post(target, name), DPromised)
}}
}
|