Comparing version 0.8.2 to 0.8.3
<!-- vim:ts=4:sts=4:sw=4:et:tw=60 --> | ||
## Next major | ||
- WARNING: The undocumented ``Method`` export will be | ||
removed. Use ``sender(op)``. | ||
- WARNING: The deprecated ``node`` export will be removed. | ||
Use ``nbind``. | ||
## 0.8.3 | ||
- Added ``isFulfilled``, ``isRejected``, and ``isResolved`` | ||
to the promise prototype. | ||
- Added ``allResolved`` for waiting for every promise to either be | ||
fulfilled or rejected, without propagating an error. @utvara #53 | ||
- Added ``Q.bind`` as a method to transform functions that | ||
return and throw into promise-returning functions. See | ||
[an example](https://gist.github.com/1782808). @domenic | ||
- Renamed ``node`` export to ``nbind``, and added ``napply`` to | ||
complete the set. ``node`` remains as deprecated. @domenic #58 | ||
- Renamed ``Method`` export to ``sender``. ``Method`` | ||
remains as deprecated and will be removed in the next | ||
major version since I expect it has very little usage. | ||
- Added browser console message indicating a live list of | ||
unhandled errors. | ||
- Added support for ``msSetImmediate`` (IE10) or ``setImmediate`` | ||
(available via [polyfill](https://github.com/NobleJS/setImmediate)) | ||
as a browser-side ``nextTick`` implementation. #44 #50 #59 | ||
- Stopped using the event-queue dependency, which was in place for | ||
Narwhal support: now directly using ``process.nextTick``. | ||
- WARNING: EXPERIMENTAL: added ``finally`` alias for ``fin``, ``catch`` | ||
alias for ``fail``, ``try`` alias for ``call``, and ``delete`` alias | ||
for ``del``. These properties are enquoted in the library for | ||
cross-browser compatibility, but may be used as property names in | ||
modern engines. | ||
## 0.8.2 | ||
- Deprecated ``ref`` in favor of ``resolve`` as recommended by | ||
@domenicdenicola. | ||
@domenic. | ||
- Update event-queue dependency. | ||
@@ -11,4 +45,4 @@ | ||
- Fixed opera bug. #35 @cadorn | ||
- Fixed ``Q.all([])`` #32 @domenicdenicola | ||
- Fixed Opera bug. #35 @cadorn | ||
- Fixed ``Q.all([])`` #32 @domenic | ||
@@ -24,3 +58,3 @@ ## 0.8.0 | ||
- WARNING: ``wait`` removed. Do ``all(args).get(0)`` instead. | ||
- WARNING: ``join`` removed. Do ``all(args).spread(callback) instead. | ||
- WARNING: ``join`` removed. Do ``all(args).spread(callback)`` instead. | ||
- WARNING: Removed the ``Q`` function module.exports alias | ||
@@ -27,0 +61,0 @@ for ``Q.ref``. It conflicts with ``Q.apply`` in weird |
{ | ||
"name": "q", | ||
"version": "0.8.2", | ||
"version": "0.8.3", | ||
"description": "A library for promises (CommonJS/Promises/A,B,D)", | ||
"homepage": "http://github.com/kriskowal/q/", | ||
"author": "Kris Kowal <kris@cixar.com> (http://github.com/kriskowal/)", | ||
"keywords": [ | ||
"q", | ||
"promise", | ||
"deferred", | ||
"future", | ||
"async", | ||
"fluent", | ||
"browser", | ||
"node" | ||
], | ||
"contributors": [ | ||
"Kris Kowal <kris@cixar.com> (http://github.com/kriskowal/)", | ||
"Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)" | ||
"Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)", | ||
"Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)" | ||
], | ||
@@ -30,7 +41,6 @@ "bugs": { | ||
}, | ||
"dependencies": { | ||
"event-queue": "0.2.0" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"test": ">=0.3.0" | ||
"test": ">=0.3.0", | ||
"jshint": "*" | ||
}, | ||
@@ -43,3 +53,2 @@ "scripts": { | ||
"dependencies": { | ||
"event-queue": ">=0.2.0", | ||
"system": ">=0.0.4" | ||
@@ -46,0 +55,0 @@ } |
362
q.js
// vim:ts=4:sts=4:sw=4: | ||
/*jshint browser: true, node: true, | ||
curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true, undef: true | ||
*/ | ||
/*global define: false, Q: true */ | ||
/*! | ||
@@ -22,57 +26,57 @@ * | ||
if (typeof define === "function") { | ||
define(definition); | ||
define(["exports"], definition); | ||
// CommonJS | ||
} else if (typeof exports === "object") { | ||
definition(require, exports); | ||
definition(exports); | ||
// <script> | ||
} else { | ||
definition(void 0, Q = {}); | ||
definition(Q = {}); | ||
} | ||
})(function (serverSideRequire, exports) { | ||
})(function (exports) { | ||
"use strict"; | ||
var nextTick; | ||
try { | ||
// Narwhal, Node (with a package, wraps process.nextTick) | ||
// "require" is renamed to "serverSideRequire" so | ||
// client-side scrapers do not try to load | ||
// "event-queue". | ||
nextTick = serverSideRequire("event-queue").enqueue; | ||
} catch (e) { | ||
// browsers | ||
if (typeof MessageChannel !== "undefined") { | ||
// modern browsers | ||
// http://www.nonblocking.io/2011/06/windownexttick.html | ||
var channel = new MessageChannel(); | ||
// linked list of tasks (single, with head node) | ||
var head = {}, tail = head; | ||
channel.port1.onmessage = function () { | ||
var next = head.next; | ||
var task = next.task; | ||
head = next; | ||
task(); | ||
}; | ||
nextTick = function (task) { | ||
tail = tail.next = {task: task}; | ||
channel.port2.postMessage(0); | ||
}; | ||
} else { | ||
// old browsers | ||
nextTick = function (task) { | ||
setTimeout(task, 0); | ||
}; | ||
} | ||
if (typeof process !== "undefined") { | ||
// node | ||
nextTick = process.nextTick; | ||
} else if (typeof msSetImmediate === "function") { | ||
// IE 10 only, at the moment | ||
nextTick = msSetImmediate; | ||
} else if (typeof setImmediate === "function") { | ||
// https://github.com/NobleJS/setImmediate | ||
nextTick = setImmediate; | ||
} else if (typeof MessageChannel !== "undefined") { | ||
// modern browsers | ||
// http://www.nonblocking.io/2011/06/windownexttick.html | ||
var channel = new MessageChannel(); | ||
// linked list of tasks (single, with head node) | ||
var head = {}, tail = head; | ||
channel.port1.onmessage = function () { | ||
head = head.next; | ||
var task = head.task; | ||
head.task = null; | ||
task(); | ||
}; | ||
nextTick = function (task) { | ||
tail = tail.next = {task: task}; | ||
channel.port2.postMessage(0); | ||
}; | ||
} else { | ||
// old browsers | ||
nextTick = function (task) { | ||
setTimeout(task, 0); | ||
}; | ||
} | ||
// useful for an identity stub and default resolvers | ||
function identity (x) {return x;} | ||
function identity(x) { return x; } | ||
// shims | ||
var shim = function (object, name, shim) { | ||
if (!object[name]) | ||
object[name] = shim; | ||
function shim(object, name, shimmed) { | ||
if (!object[name]) { | ||
object[name] = shimmed; | ||
} | ||
return object[name]; | ||
}; | ||
} | ||
@@ -82,3 +86,3 @@ var freeze = shim(Object, "freeze", identity); | ||
var create = shim(Object, "create", function (prototype) { | ||
var Type = function () {}; | ||
function Type() { } | ||
Type.prototype = prototype; | ||
@@ -90,4 +94,5 @@ return new Type(); | ||
var keys = []; | ||
for (var key in object) | ||
for (var key in object) { | ||
keys.push(key); | ||
} | ||
return keys; | ||
@@ -100,3 +105,3 @@ }); | ||
// concerning the initial value, if one is not provided | ||
if (arguments.length == 1) { | ||
if (arguments.length === 1) { | ||
// seek to the first value in the array, accounting | ||
@@ -109,4 +114,5 @@ // for the possibility that is is a sparse array | ||
} | ||
if (++i >= ii) | ||
if (++i >= ii) { | ||
throw new TypeError(); | ||
} | ||
} while (1); | ||
@@ -124,11 +130,12 @@ } | ||
var isStopIteration = function (exception) { | ||
return Object.prototype.toString.call(exception) | ||
=== "[object StopIteration]"; | ||
}; | ||
function isStopIteration(exception) { | ||
return Object.prototype.toString.call(exception) === | ||
"[object StopIteration]"; | ||
} | ||
// Abbreviations for performance and minification | ||
var slice = Array.prototype.slice; | ||
var valueOf = function (value) { | ||
if (value === void 0 || value === null) { | ||
function valueOf(value) { | ||
// if !Object.isObject(value) | ||
if (Object(value) !== value) { | ||
return value; | ||
@@ -138,3 +145,3 @@ } else { | ||
} | ||
}; | ||
} | ||
@@ -168,3 +175,3 @@ /** | ||
var deferred = create(defer.prototype); | ||
var promise = create(Promise.prototype); | ||
var promise = create(makePromise.prototype); | ||
@@ -183,11 +190,12 @@ promise.promiseSend = function () { | ||
promise.valueOf = function () { | ||
if (pending) | ||
if (pending) { | ||
return promise; | ||
} | ||
return value.valueOf(); | ||
}; | ||
var become = function (resolvedValue) { | ||
var i, ii, task; | ||
if (!pending) | ||
function become(resolvedValue) { | ||
if (!pending) { | ||
return; | ||
} | ||
value = resolve(resolvedValue); | ||
@@ -201,3 +209,3 @@ reduce.call(pending, function (undefined, pending) { | ||
return value; | ||
}; | ||
} | ||
@@ -237,5 +245,4 @@ deferred.promise = freeze(promise); | ||
*/ | ||
exports.makePromise = Promise; | ||
function Promise(descriptor, fallback, valueOf) { | ||
exports.makePromise = makePromise; | ||
function makePromise(descriptor, fallback, valueOf, rejected) { | ||
if (fallback === void 0) { | ||
@@ -247,3 +254,3 @@ fallback = function (op) { | ||
var promise = create(Promise.prototype); | ||
var promise = create(makePromise.prototype); | ||
@@ -255,5 +262,5 @@ promise.promiseSend = function (op, resolved /* ...args */) { | ||
if (descriptor[op]) { | ||
result = descriptor[op].apply(descriptor, args); | ||
result = descriptor[op].apply(promise, args); | ||
} else { | ||
result = fallback.apply(descriptor, [op].concat(args)); | ||
result = fallback.apply(promise, [op].concat(args)); | ||
} | ||
@@ -266,10 +273,15 @@ } catch (exception) { | ||
if (valueOf) | ||
if (valueOf) { | ||
promise.valueOf = valueOf; | ||
} | ||
if (rejected) { | ||
promise.promiseRejected = true; | ||
} | ||
return freeze(promise); | ||
}; | ||
} | ||
// provide thenables, CommonJS/Promises/A | ||
Promise.prototype.then = function (fulfilled, rejected) { | ||
makePromise.prototype.then = function (fulfilled, rejected) { | ||
return when(this, fulfilled, rejected); | ||
@@ -281,2 +293,3 @@ }; | ||
[ | ||
"isResolved", "isFulfilled", "isRejected", | ||
"when", "spread", "send", | ||
@@ -286,11 +299,10 @@ "get", "put", "del", | ||
"keys", | ||
"apply", "call", | ||
"all", "wait", "join", | ||
"fail", "fin", | ||
"apply", "call", "bind", | ||
"all", "allResolved", | ||
"view", "viewInfo", | ||
"timeout", "delay", | ||
"end" | ||
"catch", "finally", "fail", "fin", "end" | ||
], | ||
function (prev, name) { | ||
Promise.prototype[name] = function () { | ||
makePromise.prototype[name] = function () { | ||
return exports[name].apply( | ||
@@ -303,13 +315,13 @@ exports, | ||
void 0 | ||
) | ||
); | ||
Promise.prototype.toSource = function () { | ||
makePromise.prototype.toSource = function () { | ||
return this.toString(); | ||
}; | ||
Promise.prototype.toString = function () { | ||
makePromise.prototype.toString = function () { | ||
return '[object Promise]'; | ||
}; | ||
freeze(Promise.prototype); | ||
freeze(makePromise.prototype); | ||
@@ -323,3 +335,3 @@ /** | ||
return object && typeof object.promiseSend === "function"; | ||
}; | ||
} | ||
@@ -331,4 +343,4 @@ /** | ||
function isResolved(object) { | ||
return !isPromise(valueOf(object)); | ||
}; | ||
return isFulfilled(object) || isRejected(object); | ||
} | ||
@@ -341,4 +353,4 @@ /** | ||
function isFulfilled(object) { | ||
return !isPromise(valueOf(object)) && !isRejected(object); | ||
}; | ||
return !isPromise(valueOf(object)); | ||
} | ||
@@ -351,7 +363,15 @@ /** | ||
object = valueOf(object); | ||
if (object === void 0 || object === null) | ||
return false; | ||
return !!object.promiseRejected; | ||
return object && !!object.promiseRejected; | ||
} | ||
var rejections = []; | ||
var errors = []; | ||
if (typeof window !== "undefined") { | ||
// This promise library consumes exceptions thrown in handlers so | ||
// they can be handled by a subsequent promise. The rejected | ||
// promises get added to this array when they are created, and | ||
// removed when they are handled. | ||
console.log("Should be empty:", errors); | ||
} | ||
/** | ||
@@ -363,4 +383,12 @@ * Constructs a rejected promise. | ||
function reject(reason) { | ||
return Promise({ | ||
var rejection = makePromise({ | ||
"when": function (rejected) { | ||
// note that the error has been handled | ||
if (rejected) { | ||
var at = rejections.indexOf(this); | ||
if (at !== -1) { | ||
errors.splice(at, 1); | ||
rejections.splice(at, 1); | ||
} | ||
} | ||
return rejected ? rejected(reason) : reject(reason); | ||
@@ -371,13 +399,10 @@ } | ||
}, function valueOf() { | ||
var rejection = create(reject.prototype); | ||
rejection.promiseRejected = true; | ||
rejection.reason = reason; | ||
return rejection; | ||
}); | ||
return reject(reason); | ||
}, true); | ||
// note that the error has not been handled | ||
rejections.push(rejection); | ||
errors.push(reason); | ||
return rejection; | ||
} | ||
reject.prototype = create(Promise.prototype, { | ||
constructor: { value: reject } | ||
}); | ||
/** | ||
@@ -388,3 +413,3 @@ * Constructs a promise for an immediate reference. | ||
exports.resolve = resolve; | ||
exports.ref = resolve; // XXX Deprecated | ||
exports.ref = resolve; // XXX deprecated | ||
function resolve(object) { | ||
@@ -394,4 +419,5 @@ // If the object is already a Promise, return it directly. This enables | ||
// but to tolerably coerce non-promises to promises. | ||
if (isPromise(object)) | ||
if (isPromise(object)) { | ||
return object; | ||
} | ||
// assimilate thenables, CommonJS/Promises/A | ||
@@ -403,3 +429,3 @@ if (object && typeof object.then === "function") { | ||
} | ||
return Promise({ | ||
return makePromise({ | ||
"when": function (rejected) { | ||
@@ -426,7 +452,11 @@ return object; | ||
var properties = {}; | ||
function fixFalsyProperty(name) { | ||
if (!properties[name]) { | ||
properties[name] = typeof on[name]; | ||
} | ||
} | ||
while (on) { | ||
Object.getOwnPropertyNames(on).forEach(function (name) { | ||
if (!properties[name]) | ||
properties[name] = typeof on[name]; | ||
}); | ||
Object.getOwnPropertyNames(on).forEach(fixFalsyProperty); | ||
on = Object.getPrototypeOf(on); | ||
@@ -437,3 +467,3 @@ } | ||
"properties": properties | ||
} | ||
}; | ||
}, | ||
@@ -459,3 +489,3 @@ "keys": function () { | ||
function master(object) { | ||
return Promise({ | ||
return makePromise({ | ||
"isDef": function () {} | ||
@@ -474,3 +504,3 @@ }, function fallback(op) { | ||
if (info) { | ||
return Promise({ | ||
return makePromise({ | ||
"viewInfo": function () { | ||
@@ -486,3 +516,3 @@ return info; | ||
} else { | ||
return send(object, "viewInfo") | ||
return send(object, "viewInfo"); | ||
} | ||
@@ -553,4 +583,5 @@ } | ||
resolve(value).promiseSend("when", function (value) { | ||
if (done) | ||
if (done) { | ||
return; | ||
} | ||
done = true; | ||
@@ -562,4 +593,5 @@ deferred.resolve( | ||
}, function (reason) { | ||
if (done) | ||
if (done) { | ||
return; | ||
} | ||
done = true; | ||
@@ -618,3 +650,3 @@ deferred.resolve(_rejected(reason)); | ||
// when verb is "throw", arg is a reason/error | ||
var continuer = function (verb, arg) { | ||
function continuer(verb, arg) { | ||
var result; | ||
@@ -631,3 +663,3 @@ try { | ||
return when(result, callback, errback); | ||
}; | ||
} | ||
var generator = makeGenerator.apply(this, arguments); | ||
@@ -644,6 +676,7 @@ var callback = continuer.bind(continuer, "send"); | ||
* | ||
* "Method" constructs methods like "get(promise, name)" and "put(promise)". | ||
* "sender" constructs methods like "get(promise, name)" and "put(promise)". | ||
*/ | ||
exports.Method = Method; | ||
function Method (op) { | ||
exports.sender = sender; | ||
exports.Method = sender; // XXX deprecated | ||
function sender(op) { | ||
return function (object) { | ||
@@ -682,3 +715,3 @@ var args = slice.call(arguments, 1); | ||
*/ | ||
exports.get = Method("get"); | ||
exports.get = sender("get"); | ||
@@ -692,3 +725,3 @@ /** | ||
*/ | ||
exports.put = Method("put"); | ||
exports.put = sender("put"); | ||
@@ -701,3 +734,3 @@ /** | ||
*/ | ||
exports.del = Method("del"); | ||
exports.del = exports['delete'] = sender("del"); | ||
@@ -716,3 +749,3 @@ /** | ||
*/ | ||
var post = exports.post = Method("post"); | ||
var post = exports.post = sender("post"); | ||
@@ -737,3 +770,3 @@ /** | ||
*/ | ||
var apply = exports.apply = Method("apply"); | ||
var apply = exports.apply = sender("apply"); | ||
@@ -746,8 +779,43 @@ /** | ||
*/ | ||
var call = exports.call = function (value, context) { | ||
exports.call = exports['try'] = call; | ||
function call(value, context) { | ||
var args = slice.call(arguments, 2); | ||
return apply(value, context, args); | ||
}; | ||
} | ||
/** | ||
* Binds the promised function, transforming return values into a fulfilled | ||
* promise and thrown errors into a rejected one. | ||
* @param object promise or immediate reference for target function | ||
* @param context the context object (this) for the call | ||
* @param ...args array of application arguments | ||
*/ | ||
exports.bind = bind; | ||
function bind(value, context) { | ||
var args = slice.call(arguments, 2); | ||
return function bound() { | ||
var allArgs = args.concat(slice.call(arguments)); | ||
if (this instanceof bound) { | ||
var F = function () { }; | ||
F.prototype = value.prototype; | ||
var self = new F(); | ||
var result = apply(value, self, allArgs); | ||
return result.then(function (fulfilledValue) { | ||
// if Object.isObject(fulfilledValue) | ||
if (Object(fulfilledValue) === fulfilledValue) { | ||
return fulfilledValue; | ||
} | ||
return self; | ||
}); | ||
} else { | ||
return apply(value, context, allArgs); | ||
} | ||
}; | ||
} | ||
/** | ||
* Requests the names of the owned properties of a promised | ||
@@ -758,3 +826,3 @@ * object in a future turn. | ||
*/ | ||
exports.keys = Method("keys"); | ||
exports.keys = sender("keys"); | ||
@@ -774,4 +842,5 @@ /** | ||
var countDown = promises.length; | ||
if (countDown === 0) | ||
if (countDown === 0) { | ||
return resolve(promises); | ||
} | ||
var deferred = defer(); | ||
@@ -781,6 +850,7 @@ reduce.call(promises, function (undefined, promise, index) { | ||
promises[index] = value; | ||
if (--countDown === 0) | ||
if (--countDown === 0) { | ||
deferred.resolve(promises); | ||
} | ||
}) | ||
.fail(deferred.reject) | ||
.fail(deferred.reject); | ||
}, void 0); | ||
@@ -791,2 +861,13 @@ return deferred.promise; | ||
exports.allResolved = allResolved; | ||
function allResolved(promises) { | ||
return when(promises, function (promises) { | ||
return when(all(promises.map(function (promise) { | ||
return when(promise, identity, identity); | ||
})), function () { | ||
return promises.map(resolve); | ||
}); | ||
}); | ||
} | ||
/** | ||
@@ -801,2 +882,3 @@ * Captures the failure of a promise, giving an oportunity to recover | ||
*/ | ||
exports['catch'] = | ||
exports.fail = fail; | ||
@@ -812,3 +894,3 @@ function fail(promise, rejected) { | ||
* The callback can return a promise to defer completion. | ||
* @param {Any*} promise | ||
* @param {Any*} promise | ||
* @param {Function} callback to observe the resolution of the given | ||
@@ -819,2 +901,3 @@ * promise, takes no arguments. | ||
*/ | ||
exports['finally'] = | ||
exports.fin = fin; | ||
@@ -859,3 +942,3 @@ function fin(promise, callback) { | ||
exports.timeout = timeout; | ||
function timeout(promise, timeout) { | ||
function timeout(promise, ms) { | ||
var deferred = defer(); | ||
@@ -865,3 +948,3 @@ when(promise, deferred.resolve, deferred.reject); | ||
deferred.reject("Timed out"); | ||
}, timeout); | ||
}, ms); | ||
return deferred.promise; | ||
@@ -895,3 +978,3 @@ } | ||
* | ||
* Q.node(FS.readFile)(__filename) | ||
* Q.nbind(FS.readFile, FS)(__filename) | ||
* .then(console.log) | ||
@@ -901,4 +984,5 @@ * .end() | ||
*/ | ||
exports.node = node; | ||
function node(callback /* thisp, ...args*/) { | ||
exports.nbind = nbind; | ||
exports.node = nbind; // XXX deprecated | ||
function nbind(callback /* thisp, ...args*/) { | ||
if (arguments.length > 1) { | ||
@@ -921,6 +1005,7 @@ var args = Array.prototype.slice.call(arguments, 1); | ||
/** | ||
* Passes a continuation to a Node function and returns a promise. | ||
* Passes a continuation to a Node function, which is called with a given | ||
* `this` value and arguments provided as an array, and returns a promise. | ||
* | ||
* var FS = require("fs"); | ||
* Q.ncall(FS.readFile, __filename) | ||
* Q.napply(FS.readFile, FS, [__filename]) | ||
* .then(function (content) { | ||
@@ -930,8 +1015,23 @@ * }) | ||
*/ | ||
exports.napply = napply; | ||
function napply(callback, thisp, args) { | ||
return nbind(callback).apply(thisp, args); | ||
} | ||
/** | ||
* Passes a continuation to a Node function, which is called with a given | ||
* `this` value and arguments provided individually, and returns a promise. | ||
* | ||
* var FS = require("fs"); | ||
* Q.ncall(FS.readFile, FS, __filename) | ||
* .then(function (content) { | ||
* }) | ||
* | ||
*/ | ||
exports.ncall = ncall; | ||
function ncall(callback, thisp /*, ...args*/) { | ||
var args = slice.call(arguments, 2); | ||
return node(callback).apply(thisp, args); | ||
return napply(callback, thisp, args); | ||
} | ||
}); |
26
q.min.js
@@ -1,12 +0,14 @@ | ||
(function(n){"function"===typeof define?define(n):"object"===typeof exports?n(require,exports):n(void 0,Q={})})(function(n,d){function y(a){return a}function h(){var a=[],b,c=o(h.prototype),f=o(e.prototype);f.promiseSend=function(){var c=i.call(arguments);a?a.push(c):k(function(){b.promiseSend.apply(b,c)})};f.valueOf=function(){return a?f:b.valueOf()};var d=function(c){if(a)return b=l(c),s.call(a,function(a,c){k(function(){b.promiseSend.apply(b,c)})},void 0),a=void 0,b};c.promise=u(f);c.resolve=d; | ||
c.reject=function(a){return d(j(a))};return c}function e(a,b,c){void 0===b&&(b=function(a){return j("Promise does not support operation: "+a)});var f=o(e.prototype);f.promiseSend=function(c,f){var d=i.call(arguments,2),t;try{t=a[c]?a[c].apply(a,d):b.apply(a,[c].concat(d))}catch(e){t=j(e)}return(f||y)(t)};if(c)f.valueOf=c;return u(f)}function r(a){return a&&"function"===typeof a.promiseSend}function z(a){a=p(a);return void 0===a||null===a?!1:!!a.promiseRejected}function j(a){return e({when:function(b){return b? | ||
b(a):j(a)}},function(){return j(a)},function(){var b=o(j.prototype);b.promiseRejected=!0;b.reason=a;return b})}function l(a){if(r(a))return a;if(a&&"function"===typeof a.then){var b=h();a.then(b.resolve,b.reject);return b.promise}return e({when:function(){return a},get:function(b){return a[b]},put:function(b,f){return a[b]=f},del:function(b){return delete a[b]},post:function(b,f){return a[b].apply(a,f)},apply:function(b,f){return a.apply(b,f)},viewInfo:function(){for(var b=a,f={};b;)Object.getOwnPropertyNames(b).forEach(function(a){f[a]|| | ||
(f[a]=typeof b[a])}),b=Object.getPrototypeOf(b);return{type:typeof a,properties:f}},keys:function(){return F(a)}},void 0,function(){return a})}function A(a,b){a=l(a);return b?e({viewInfo:function(){return b}},function(b){var f=i.call(arguments);return q.apply(void 0,[a].concat(f))},function(){return p(a)}):q(a,"viewInfo")}function g(a,b,c){function f(a){try{return b?b(a):a}catch(c){return j(c)}}function d(a){try{return c?c(a):j(a)}catch(b){return j(b)}}var e=h(),g=!1;k(function(){l(a).promiseSend("when", | ||
function(a){g||(g=!0,e.resolve(l(a).promiseSend("when",f,d)))},function(a){g||(g=!0,e.resolve(d(a)))})});return e.promise}function m(a){return function(b){var c=i.call(arguments,1);return q.apply(void 0,[b,a].concat(c))}}function q(a,b){var c=h(),d=i.call(arguments,2),a=l(a);k(function(){a.promiseSend.apply(a,[b,c.resolve].concat(d))});return c.promise}function B(a){if(1<arguments.length)var b=Array.prototype.slice.call(arguments,1),a=a.bind.apply(a,b);return function(){var b=h(),d=i.call(arguments); | ||
d.push(b.node());v(a,this,d).fail(b.reject);return b.promise}}var k;try{k=n("event-queue").enqueue}catch(G){if("undefined"!==typeof MessageChannel){var C=new MessageChannel,w={},D=w;C.port1.onmessage=function(){var a=w.next,b=a.task;w=a;b()};k=function(a){D=D.next={task:a};C.port2.postMessage(0)}}else k=function(a){setTimeout(a,0)}}var x=function(a,b,c){a[b]||(a[b]=c);return a[b]},u=x(Object,"freeze",y),o=x(Object,"create",function(a){var b=function(){};b.prototype=a;return new b}),F=x(Object,"keys", | ||
function(a){var b=[],c;for(c in a)b.push(c);return b}),s=Array.prototype.reduce||function(a,b){var c=0,d=this.length;if(1==arguments.length){do{if(c in this){b=this[c++];break}if(++c>=d)throw new TypeError;}while(1)}for(;c<d;c++)c in this&&(b=a(b,this[c],c));return b},i=Array.prototype.slice,p=function(a){return void 0===a||null===a?a:a.valueOf()};d.nextTick=k;d.defer=h;h.prototype.node=function(){var a=this;return function(b,c){b?a.reject(b):2<arguments.length?a.resolve(Array.prototype.slice.call(arguments, | ||
1)):a.resolve(c)}};d.makePromise=e;e.prototype.then=function(a,b){return g(this,a,b)};s.call("when,spread,send,get,put,del,post,invoke,keys,apply,call,all,wait,join,fail,fin,view,viewInfo,timeout,delay,end".split(","),function(a,b){e.prototype[b]=function(){return d[b].apply(d,[this].concat(i.call(arguments)))}},void 0);e.prototype.toSource=function(){return this.toString()};e.prototype.toString=function(){return"[object Promise]"};u(e.prototype);d.isPromise=r;d.isResolved=function(a){return!r(p(a))}; | ||
d.isFulfilled=function(a){return!r(p(a))&&!z(a)};d.isRejected=z;d.reject=j;j.prototype=o(e.prototype,{constructor:{value:j}});d.ref=l;d.master=function(a){return e({isDef:function(){}},function(b){var c=i.call(arguments);return q.apply(void 0,[a].concat(c))},function(){return p(a)})};d.viewInfo=A;d.view=function(a){return A(a).when(function(b){var c;c="function"===b.type?function(){return v(a,void 0,arguments)}:{};var d=b.properties||{};Object.keys(d).forEach(function(b){"function"===d[b]&&(c[b]= | ||
function(){return E(a,b,arguments)})});return l(c)})};d.when=g;d.spread=function(a,b,c){return g(a,function(a){return b.apply(void 0,a)},c)};d.async=function(a){return function(){var b=function(a,b){var i;try{i=c[a](b)}catch(h){return"[object StopIteration]"===Object.prototype.toString.call(h)?h.value:j(h)}return g(i,d,e)},c=a.apply(this,arguments),d=b.bind(b,"send"),e=b.bind(b,"throw");return d()}};d.Method=m;d.send=q;d.get=m("get");d.put=m("put");d.del=m("del");var E=d.post=m("post");d.invoke=function(a, | ||
b){var c=i.call(arguments,2);return E(a,b,c)};var v=d.apply=m("apply");d.call=function(a,b){var c=i.call(arguments,2);return v(a,b,c)};d.keys=m("keys");d.all=function(a){return g(a,function(a){var c=a.length;if(0===c)return l(a);var d=h();s.call(a,function(e,h,i){g(h,function(e){a[i]=e;0===--c&&d.resolve(a)}).fail(d.reject)},void 0);return d.promise})};d.fail=function(a,b){return g(a,void 0,b)};d.fin=function(a,b){return g(a,function(a){return g(b(),function(){return a})},function(a){return g(b(), | ||
function(){return j(a)})})};d.end=function(a){g(a,void 0,function(a){k(function(){throw a;})})};d.timeout=function(a,b){var c=h();g(a,c.resolve,c.reject);setTimeout(function(){c.reject("Timed out")},b);return c.promise};d.delay=function(a,b){void 0===b&&(b=a,a=void 0);var c=h();setTimeout(function(){c.resolve(a)},b);return c.promise};d.node=B;d.ncall=function(a,b){var c=i.call(arguments,2);return B(a).apply(b,c)}}); | ||
(function(n){"function"===typeof define?define(n):"object"===typeof exports?n(require,exports):n(void 0,Q={})})(function(n,c){function s(a){return a}function u(a,b,e){a[b]||(a[b]=e);return a[b]}function o(a){return void 0===a||null===a?a:a.valueOf()}function j(){function a(a){if(b)return e=i(a),v.call(b,function(a,b){l(function(){e.promiseSend.apply(e,b)})},void 0),b=void 0,e}var b=[],e,k=p(j.prototype),c=p(f.prototype);c.promiseSend=function(){var a=g.call(arguments);b?b.push(a):l(function(){e.promiseSend.apply(e, | ||
a)})};c.valueOf=function(){return b?c:e.valueOf()};k.promise=x(c);k.resolve=a;k.reject=function(b){return a(h(b))};return k}function f(a,b,e){void 0===b&&(b=function(a){return h("Promise does not support operation: "+a)});var k=p(f.prototype);k.promiseSend=function(e,c){var d=g.call(arguments,2),w;try{w=a[e]?a[e].apply(k,d):b.apply(k,[e].concat(d))}catch(f){w=h(f)}return(c||s)(w)};e&&(k.valueOf=e);return x(k)}function t(a){return a&&"function"===typeof a.promiseSend}function B(a){a=o(a);return void 0=== | ||
a||null===a?!1:!!a.promiseRejected}function h(a){var b=f({when:function(b){if(b){var c=y.indexOf(this);-1!==c&&(z.splice(c,1),y.splice(c,1))}return b?b(a):h(a)}},function(){return h(a)},function(){var b=p(h.prototype);b.promiseRejected=!0;b.reason=a;return b});y.push(b);z.push(a);return b}function i(a){if(t(a))return a;if(a&&"function"===typeof a.then){var b=j();a.then(b.resolve,b.reject);return b.promise}return f({when:function(){return a},get:function(b){return a[b]},put:function(b,c){return a[b]= | ||
c},del:function(b){return delete a[b]},post:function(b,c){return a[b].apply(a,c)},apply:function(b,c){return a.apply(b,c)},viewInfo:function(){function b(a){d[a]||(d[a]=typeof c[a])}for(var c=a,d={};c;)Object.getOwnPropertyNames(c).forEach(b),c=Object.getPrototypeOf(c);return{type:typeof a,properties:d}},keys:function(){return J(a)}},void 0,function(){return a})}function C(a,b){a=i(a);return b?f({viewInfo:function(){return b}},function(b){var c=g.call(arguments);return q.apply(void 0,[a].concat(c))}, | ||
function(){return o(a)}):q(a,"viewInfo")}function d(a,b,e){function c(a){try{return b?b(a):a}catch(e){return h(e)}}function d(a){try{return e?e(a):h(a)}catch(b){return h(b)}}var f=j(),g=!1;l(function(){i(a).promiseSend("when",function(a){g||(g=!0,f.resolve(i(a).promiseSend("when",c,d)))},function(a){g||(g=!0,f.resolve(d(a)))})});return f.promise}function m(a){return function(b){var e=g.call(arguments,1);return q.apply(void 0,[b,a].concat(e))}}function q(a,b){var e=j(),c=g.call(arguments,2),a=i(a); | ||
l(function(){a.promiseSend.apply(a,[b,e.resolve].concat(c))});return e.promise}function D(a){return d(a,function(a){var e=a.length;if(0===e)return i(a);var c=j();v.call(a,function(f,g,h){d(g,function(d){a[h]=d;0===--e&&c.resolve(a)}).fail(c.reject)},void 0);return c.promise})}function E(a){if(1<arguments.length)var b=Array.prototype.slice.call(arguments,1),a=a.bind.apply(a,b);return function(){var b=j(),c=g.call(arguments);c.push(b.node());r(a,this,c).fail(b.reject);return b.promise}}var l;try{l= | ||
n("event-queue").enqueue}catch(K){if("undefined"!==typeof MessageChannel){var F=new MessageChannel,A={},G=A;F.port1.onmessage=function(){var a=A.next,b=a.task;A=a;b()};l=function(a){G=G.next={task:a};F.port2.postMessage(0)}}else l=function(a){setTimeout(a,0)}}var x=u(Object,"freeze",s),p=u(Object,"create",function(a){function b(){}b.prototype=a;return new b}),J=u(Object,"keys",function(a){var b=[],c;for(c in a)b.push(c);return b}),v=Array.prototype.reduce||function(a,b){var c=0,d=this.length;if(1=== | ||
arguments.length){do{if(c in this){b=this[c++];break}if(++c>=d)throw new TypeError;}while(1)}for(;c<d;c++)c in this&&(b=a(b,this[c],c));return b},g=Array.prototype.slice;c.nextTick=l;c.defer=j;j.prototype.node=function(){var a=this;return function(b,c){b?a.reject(b):2<arguments.length?a.resolve(Array.prototype.slice.call(arguments,1)):a.resolve(c)}};c.makePromise=f;f.prototype.then=function(a,b){return d(this,a,b)};v.call("isResolved,isFulfilled,isRejected,when,spread,send,get,put,del,post,invoke,keys,apply,call,bind,all,allResolved,view,viewInfo,timeout,delay,catch,finally,fail,fin,end".split(","), | ||
function(a,b){f.prototype[b]=function(){return c[b].apply(c,[this].concat(g.call(arguments)))}},void 0);f.prototype.toSource=function(){return this.toString()};f.prototype.toString=function(){return"[object Promise]"};x(f.prototype);c.isPromise=t;c.isResolved=function(a){return!t(o(a))};c.isFulfilled=function(a){return!t(o(a))&&!B(a)};c.isRejected=B;var y=[],z=[];"undefined"!==typeof window&&console.log("Should be empty:",z);c.reject=h;h.prototype=p(f.prototype,{constructor:{value:h}});c.resolve= | ||
i;c.ref=i;c.master=function(a){return f({isDef:function(){}},function(b){var c=g.call(arguments);return q.apply(void 0,[a].concat(c))},function(){return o(a)})};c.viewInfo=C;c.view=function(a){return C(a).when(function(b){var c;c="function"===b.type?function(){return r(a,void 0,arguments)}:{};var d=b.properties||{};Object.keys(d).forEach(function(b){"function"===d[b]&&(c[b]=function(){return H(a,b,arguments)})});return i(c)})};c.when=d;c.spread=function(a,b,c){return d(a,function(a){return b.apply(void 0, | ||
a)},c)};c.async=function(a){return function(){function b(a,b){var j;try{j=c[a](b)}catch(i){return"[object StopIteration]"===Object.prototype.toString.call(i)?i.value:h(i)}return d(j,f,g)}var c=a.apply(this,arguments),f=b.bind(b,"send"),g=b.bind(b,"throw");return f()}};c.sender=m;c.Method=m;c.send=q;c.get=m("get");c.put=m("put");c.del=c["delete"]=m("del");var H=c.post=m("post");c.invoke=function(a,b){var c=g.call(arguments,2);return H(a,b,c)};var r=c.apply=m("apply");c.call=c["try"]=function(a,b){var c= | ||
g.call(arguments,2);return r(a,b,c)};c.bind=function(a,b){var c=g.call(arguments,2);return function I(){var d=c.concat(g.call(arguments));if(this instanceof I){var f=function(){};f.prototype=a.prototype;var h=new f;return r(a,h,d).then(function(a){return Object(a)===a?a:h})}return r(a,b,d)}};c.keys=m("keys");c.all=D;c.allResolved=function(a){return d(a,function(a){return d(D(a.map(function(a){return d(a,s,s)})),function(){return a.map(i)})})};c["catch"]=c.fail=function(a,b){return d(a,void 0,b)}; | ||
c["finally"]=c.fin=function(a,b){return d(a,function(a){return d(b(),function(){return a})},function(a){return d(b(),function(){return h(a)})})};c.end=function(a){d(a,void 0,function(a){l(function(){throw a;})})};c.timeout=function(a,b){var c=j();d(a,c.resolve,c.reject);setTimeout(function(){c.reject("Timed out")},b);return c.promise};c.delay=function(a,b){void 0===b&&(b=a,a=void 0);var c=j();setTimeout(function(){c.resolve(a)},b);return c.promise};c.node=E;c.ncall=function(a,b){var c=g.call(arguments, | ||
2);return E(a).apply(b,c)}}); |
565
README.md
@@ -52,7 +52,6 @@ [![Build Status](https://secure.travis-ci.org/kriskowal/q.png)](http://travis-ci.org/kriskowal/q) | ||
is saying, “Don’t call me, I’ll call you.”. Promises | ||
[un-invert][IOC] the inversion, cleanly separating the | ||
handling of input argument from the handling of control | ||
flow. This simplifies the use and creation of API’s, | ||
particularly variadic parameters (spread and rest | ||
arguments). | ||
[un-invert][IOC] the inversion, cleanly separating the input | ||
arguments from control flow arguments. This simplifies the | ||
use and creation of API’s, particularly variadic, | ||
rest and spread arguments. | ||
@@ -62,8 +61,8 @@ [IOC]: http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript | ||
Getting Started | ||
=============== | ||
## Getting Started | ||
The Q module can be loaded as: | ||
- a ``<script>`` tag (creating a ``Q`` global variable) | ||
- a ``<script>`` tag (creating a ``Q`` global variable): only ~2 KB | ||
minified and gzipped! | ||
- a NodeJS and CommonJS module available from NPM as the ``q`` | ||
@@ -73,4 +72,2 @@ package | ||
Please join the Q-Continuum [mailing list](https://groups.google.com/forum/#!forum/q-continuum). | ||
Q can exchange promises with jQuery and Dojo and the following libraries | ||
@@ -91,6 +88,7 @@ are based on Q. | ||
Please join the Q-Continuum [mailing list](https://groups.google.com/forum/#!forum/q-continuum). | ||
Tutorial | ||
======== | ||
## Tutorial | ||
Promises have a ``then`` method, which you can use to get the eventual | ||
@@ -112,5 +110,11 @@ return value (fulfillment) or thrown exception (rejection). | ||
Note that resolution of a promise is always asynchronous: that is, the | ||
value or error handler will always be called in the next turn of the | ||
event loop (i.e. `process.nextTick` in Node). This gives you a nice | ||
guarantee when mentally tracing the flow of your code, namely that | ||
``then`` will always return before either handler is executed. | ||
## Propagation | ||
### Propagation | ||
The ``then`` method returns a promise, which in this example, I’m | ||
@@ -185,3 +189,3 @@ assigning to ``bar``. | ||
## Chaining | ||
### Chaining | ||
@@ -197,3 +201,3 @@ There are two ways to chain promises. You can chain promises either | ||
// if we get here without an error, | ||
// the value retuned here | ||
// the value returned here | ||
// or the exception thrown here | ||
@@ -213,3 +217,3 @@ // resolves the promise returned | ||
// if we get here without an error, | ||
// the value retuned here | ||
// the value returned here | ||
// or the exception thrown here | ||
@@ -236,3 +240,3 @@ // resolves the promise returned | ||
## Combination | ||
### Combination | ||
@@ -270,2 +274,4 @@ You can turn an array of promises into a promise for the whole, | ||
return [name, FS.read(location, "utf-8")]; | ||
// FS.read returns a promise, so this array | ||
// mixes values and promises | ||
}) | ||
@@ -276,5 +282,64 @@ .spread(function (name, text) { | ||
And you can use ``Q.spread`` directly on an array of promises. | ||
## Handling Errors | ||
```javascript | ||
function eventualAdd(a, b) { | ||
return Q.spread([a, b], function (a, b) { | ||
return a + b; | ||
}) | ||
} | ||
``` | ||
The ``all`` function returns a promise for an array of values. If one | ||
of the given promise fails, the whole returned promise fails, not | ||
waiting for the rest of the batch. If you want to wait for all of the | ||
promises to either be fulfilled or rejected, you can use | ||
``allResolved``. | ||
```javascript | ||
Q.allResolved(promises) | ||
.then(function (promises) { | ||
promises.forEach(function (promise) { | ||
if (promise.isFulfilled()) { | ||
var value = promise.valueOf(); | ||
} else { | ||
} | ||
}) | ||
}) | ||
``` | ||
### Sequences | ||
If you have a number of promise-producing functions that need | ||
to be run sequentially, you can of course do so manually: | ||
```javascript | ||
return foo(initialVal).then(bar).then(baz).then(quux); | ||
``` | ||
However, if you want to run a dynamically constructed sequence of | ||
functions, you'll want something like this: | ||
```javascript | ||
var funcs = [foo, bar, baz, quux]; | ||
var result = Q.resolve(initialVal); | ||
funcs.forEach(function (f) { | ||
result = result.then(f); | ||
}); | ||
return result; | ||
``` | ||
You can make this slightly more compact using `reduce`: | ||
```javascript | ||
return funcs.reduce(function (soFar, f) { | ||
return soFar.then(f); | ||
}, Q.resolve(initialVal)); | ||
``` | ||
### Handling Errors | ||
One sometimes-unintuive aspect of promises is that if you throw an | ||
@@ -312,3 +377,3 @@ exception in the value handler, it will not be be caught by the error | ||
## The End | ||
### The End | ||
@@ -346,3 +411,3 @@ When you get to the end of a chain of promises, you should either | ||
## The Beginning | ||
### The Beginning | ||
@@ -429,3 +494,3 @@ Everything above assumes you get a promise from somewhere else. This | ||
## The Middle | ||
### The Middle | ||
@@ -483,3 +548,3 @@ If you are using a function that may return a promise, but just might | ||
## Over the Wire | ||
### Over the Wire | ||
@@ -535,3 +600,3 @@ A promise can serve as a proxy for another object, even a remote | ||
## Adapting Node | ||
### Adapting Node | ||
@@ -553,453 +618,31 @@ There is a ``node`` method on deferreds that is handy for the NodeJS | ||
There is also a ``Q.node`` function that that creates a reusable | ||
There is also a ``Q.nbind`` function that that creates a reusable | ||
wrapper. | ||
```javascript | ||
var readFile = Q.node(FS.readFile, FS) | ||
var readFile = Q.nbind(FS.readFile, FS) | ||
return readFile("foo.txt", "utf-8"); | ||
``` | ||
Note that, since promises are always resolved in the next turn of the | ||
event loop, working with streams [can be tricky][streams]. The | ||
essential problem is that, since Node does not buffer input, it is | ||
necessary to attach your ``"data"`` event listeners immediately, | ||
before this next turn comes around. There are a variety of solutions | ||
to this problem, and even some hope that in future versions of Node it | ||
will [be ameliorated][streamsnext]. | ||
API | ||
--- | ||
[streams]: https://groups.google.com/d/topic/q-continuum/xr8znxc_K5E/discussion | ||
[streamsnext]: http://maxogden.com/node-streams#streams.next | ||
## ``when(value, fulfilled_opt, rejected_opt)`` | ||
## Reference | ||
Arranges for ``fulfilled`` to be called: | ||
A method-by-method [Q API reference][reference] is available on the wiki. | ||
- with the value as its sole argument | ||
- in a future turn of the event loop | ||
- if and when the value is or becomes a fully resolved | ||
[reference]: q/wiki/API-Reference | ||
Arranges for ``rejected`` to be called: | ||
--- | ||
- with a value respresenting the reason why the object will | ||
never be resolved, typically an ``Error`` object. | ||
- in a future turn of the event loop | ||
- if the value is a promise and | ||
- if and when the promise is rejected | ||
Returns a promise: | ||
- that will resolve to the value returned by either of the | ||
callbacks, if either of those functions are called, or | ||
- that will be rejected if the value is rejected and no | ||
``rejected`` callback is provided, thus forwarding | ||
rejections by default. | ||
The value may be truly __any__ value. It can be a function. | ||
It can be a promise. | ||
Either callback may be falsy, in which case it will not be | ||
called. | ||
Guarantees: | ||
- ``fulfilled`` will not be called before when returns. | ||
- ``rejected`` will not be called before when returns. | ||
- ``fulfilled`` will not be called more than once. | ||
- ``rejected`` will not be called more than once. | ||
- If ``fulfilled`` is called, ``rejected`` will never be called. | ||
- If ``rejected`` is called, ``fulfilled`` will never be called. | ||
- If a promise is never resolved, neither callback will | ||
ever be called. | ||
THIS IS COOL | ||
- You can set up an entire chain of causes and effects in the | ||
duration of a single event and be guaranteed that any invariants | ||
in your lexical scope will not...vary. | ||
- You can both receive a promise from a sketchy API and return a | ||
promise to some other sketchy API and, as long as you trust this | ||
module, all of these guarantees are still provided. | ||
- You can use when to compose promises in a variety of ways, for | ||
example: | ||
INTERSECTION | ||
function and(a, b) { | ||
return Q.when(a, function (a) { | ||
return Q.when(b, function (b) { | ||
// ... | ||
}); | ||
}) | ||
} | ||
## ``defer()`` | ||
Returns a "deferred" object with a: | ||
- ``promise`` property | ||
- ``resolve(value)`` function | ||
- ``reject(reason)`` function | ||
- ``node()`` function | ||
The promise is suitable for passing as a value to the | ||
``when`` function, among others. | ||
Calling resolve with a promise notifies all observers that | ||
they must now wait for that promise to resolve. | ||
Calling resolve with a rejected promise notifies all | ||
observers that the promise will never be fully resolved with | ||
the rejection reason. This forwards through the the chain | ||
of ``when`` calls and their returned promises until it | ||
reaches a ``when`` call that has a ``rejected`` callback. | ||
Calling resolve with a fully resolved value notifies all | ||
observers that they may proceed with that value in a future | ||
turn. This forwards through the ``fulfilled`` chain of any | ||
pending ``when`` calls. | ||
Calling ``reject`` with a reason is equivalent to resolving | ||
with a rejection. | ||
In all cases where the resolution of a promise is set, | ||
(promise, rejection, value) the resolution is permanent and | ||
cannot be reset. All future observers of the resolution of | ||
the promise will be notified of the resolved value, so it is | ||
safe to call ``when`` on a promise regardless of whether it | ||
has been or will be resolved. | ||
Calling ``node()`` returns a callback suitable for passing | ||
to a Node function. | ||
THIS IS COOL | ||
The Deferred separates the promise part from the resolver | ||
part. So: | ||
- You can give the promise to any number of consumers and | ||
all of them will observe the resolution independently. | ||
Because the capability of observing a promise is | ||
separated from the capability of resolving the promise, | ||
none of the recipients of the promise have the ability | ||
to "trick" other recipients with misinformation. | ||
- You can give the resolver to any number of producers and | ||
whoever resolves the promise first wins. Furthermore, | ||
none of the producers can observe that they lost unless | ||
you give them the promise part too. | ||
UNION | ||
function or(a, b) { | ||
var union = Q.defer(); | ||
Q.when(a, union.resolve); | ||
Q.when(b, union.resolve); | ||
return union.promise; | ||
} | ||
## ``resolve(value)`` | ||
If value is a promise, returns the promise. | ||
If value is not a promise, returns a promise that has | ||
already been fulfilled with the given value. | ||
## ``reject(reason)`` | ||
Returns a promise that has already been rejected with the | ||
given reason. | ||
This is useful for conditionally forwarding a rejection | ||
through an errback. | ||
Q.when(API.getPromise(), function (value) { | ||
return doSomething(value); | ||
}, function (reason) { | ||
if (API.stillPossible()) { | ||
return API.tryAgain(); | ||
} else { | ||
return Q.reject(reason); | ||
} | ||
}) | ||
Unconditionally forwarding a rejection is equivalent to | ||
omitting an errback on a when call. | ||
Q.when(API.getPromise(), function (value) { | ||
return doSomething(value); | ||
}, function (reason) { | ||
return Q.reject(reason); | ||
}) | ||
Simplifies to: | ||
Q.when(API.getPromise(), function (value) { | ||
return doSomething(value); | ||
}) | ||
## ``isPromise(value)`` | ||
Returns whether the given value is a promise. | ||
## ``isResolved(value)`` | ||
Returns whether the given value is fulfilled or rejected. | ||
Non-promise values are equivalent to fulfilled promises. | ||
## ``isFulfilled(value)`` | ||
Returns whether the given value is fulfilled. Non-promise | ||
values are equivalent to fulfilled promises. | ||
## ``isRejected(value)`` | ||
Returns whether the given value is a rejected promise. | ||
## ``end(promise)`` | ||
Accepts a promise that is intended to be the last promise in | ||
a chain of promises. If an error propagates to the end of | ||
the promise chain, it will be thrown as an exception and | ||
handled by either NodeJS or the browser as an uncaught | ||
exception. | ||
## ``enqueue(callback Function)`` | ||
Calls ``callback`` in a future turn. | ||
ADVANCED API | ||
------------ | ||
The ``ref`` promise constructor establishes the basic API | ||
for performing operations on objects: "get", "put", "del", | ||
"post", "apply", and "keys". This set of "operators" can be | ||
extended by creating promises that respond to messages with | ||
other operator names, and by sending corresponding messages | ||
to those promises. | ||
## ``makePromise(handlers, fallback_opt, valueOf_opt)`` | ||
Creates a stand-alone promise that responds to messages. | ||
These messages have an operator like "when", "get", "put", | ||
and "post", corresponding to each of the above functions for | ||
sending messages to promises. | ||
The ``handlers`` are an object with function properties | ||
corresponding to operators. When the made promise receives | ||
a message and a corresponding operator exists in the | ||
``handlers``, the function gets called with the variadic | ||
arguments sent to the promise. If no ``handlers`` object | ||
exists, the ``fallback`` function is called with the operator, | ||
and the subsequent variadic arguments instead. These | ||
functions return a promise for the eventual resolution of | ||
the promise returned by the message-sender. The default | ||
fallback returns a rejection. | ||
The ``valueOf`` function, if provided, overrides the | ||
``valueOf`` function of the returned promise. This is useful | ||
for providing information about the promise in the same turn | ||
of the event loop. For example, resolved promises return | ||
their resolution value and rejections return an object that | ||
is recognized by ``isRejected``. | ||
## ``send(value, operator, ...args)`` | ||
Sends an arbitrary message to a promise. | ||
Care should be taken not to introduce control-flow hazards | ||
and security holes when forwarding messages to promises. | ||
The functions above, particularly ``when``, are carefully | ||
crafted to prevent a poorly crafted or malicious promise | ||
from breaking the invariants like not applying callbacks | ||
multiple times or in the same turn of the event loop. | ||
## ``get(object, name)`` | ||
Returns a promise for the named property of an object, | ||
albeit a promise for an object. | ||
## ``put(object, name, value)`` | ||
Returns a promise to set the named property of an object, | ||
albeit a promise, to the given value. | ||
## ``del(object, name)`` | ||
Returns a promise to delete the named property of an object, | ||
albeit a promise. | ||
## ``post(object, name, arguments)`` | ||
Returns a promise to call the named function property of an | ||
eventually fulfilled object with the given array of | ||
arguments. The object itself is ``this`` in the function. | ||
## ``invoke(object, name, ...arguments)`` | ||
Returns a promise to call the named function property of an | ||
eventually fulfilled object with the given variadic | ||
arguments. The object itself is ``this`` in the function. | ||
## ``keys(object)`` | ||
Returns a promise for an array of the property names of the | ||
eventually fulfilled object. | ||
## ``apply(function, this, arguments)`` | ||
Returns a promise for the result of calling an eventually | ||
fulfilled function, with the given values for the ``this`` | ||
and ``arguments`` array in that function. | ||
## ``call(function, this, ...arguments)`` | ||
Returns a promise for the result of eventually calling the | ||
fulfilled function, with the given context and variadic | ||
arguments. | ||
## ``all([...promises])`` | ||
Returns a promise for an array of the fulfillment of each | ||
respective promise, or rejects when the first promise is | ||
rejected. | ||
## ``fail(promise, callback())`` | ||
Accepts a promise and captures rejection with the callback, | ||
giving the callback an opportunity to recover from the | ||
failure. If the promise gets rejected, the return value of | ||
the callback resolves the returned promise. Otherwise, the | ||
fulfillment gets forwarded. | ||
## ``fin(promise, callback())`` | ||
Like a ``finally`` clause, allows you to observe either the | ||
fulfillment or rejection of a callback, but to do so without | ||
modifying the final value. This is useful for collecting | ||
resources regardless of whether a job succeeded, like | ||
closing a database connection, shutting a server down, or | ||
deleting an unneeded key from an object. The callback | ||
receives no arguments. | ||
## ``end(promise)`` | ||
Accepts a promise and returns ``undefined``, to terminate a | ||
chain of promises at the end of a program. If the promise | ||
is rejected, throws it as an exception in a future turn of | ||
the event loop. | ||
Since exceptions thrown in ``when`` callbacks are consumed | ||
and transformed into rejections, exceptions are easy to | ||
accidentally silently ignore. It is furthermore non-trivial | ||
to get those exceptions reported since the obvious way to do | ||
this is to use ``when`` to register a rejection callback, | ||
where ``throw`` would just get consumed again. ``end`` | ||
arranges for the error to be thrown in a future turn of the | ||
event loop, so it won't be caught; it will cause the | ||
exception to emit a browser's ``onerror`` event or NodeJS's | ||
``process`` ``"uncaughtException"``. | ||
## ``async(generatorFunction)`` | ||
This is an experimental tool for converting a generator | ||
function into a deferred function. This has the potential | ||
of reducing nested callbacks in engines that support | ||
``yield``. See ``examples/async-generators/README.md`` for | ||
further information. | ||
## ``node(nodeFunction)`` | ||
Wraps a Node function so that it returns a promise instead | ||
of accepting a callback. | ||
```javascript | ||
var readFile = FS.node(FS.readFile); | ||
readFile("foo.txt") | ||
.then(function (text) { | ||
}); | ||
``` | ||
The ``this`` of the call gets forwarded. | ||
```javascript | ||
var readFile = FS.node(FS.readFile); | ||
FS.readFile.call(FS, "foo.txt") | ||
.then(function (text) { | ||
}); | ||
``` | ||
The ``node`` call can also be used to bind and partially | ||
apply. | ||
```javascript | ||
var readFoo = FS.node(FS.readFile, FS, "foo.txt"); | ||
readFoo() | ||
.then(function (text) { | ||
}); | ||
``` | ||
## ``ncall(nodeFunction, thisp, ...args)`` | ||
Calls a Node function, returning a promise so you don’t have | ||
to pass a callback. | ||
```javascript | ||
Q.ncall(FS.readFile, FS, "foo.txt") | ||
.then(function (text) { | ||
}); | ||
``` | ||
Chaining | ||
-------- | ||
Promises created by the Q API support chaining for some | ||
functions. The ``this`` promise becomes the first argument | ||
of the corresponding Q API function. For example, the | ||
following are equivalent: | ||
- ``when(promise, fulfilled)`` and | ||
``promise.then(fulfilled)``. | ||
- ``end(promise)`` and ``promise.end()``. | ||
The following functions are supported for chaining: | ||
- ``.when`` (``.then``) | ||
- ``.get`` | ||
- ``.put`` | ||
- ``.del`` | ||
- ``.post`` | ||
- ``.invoke`` | ||
- ``.apply`` | ||
- ``.call`` | ||
- ``.keys`` | ||
- ``.all`` | ||
- ``.fin`` | ||
- ``.end`` | ||
Copyright 2009-2011 Kristopher Michael Kowal | ||
Copyright 2009-2012 Kristopher Michael Kowal | ||
MIT License (enclosed) | ||
@@ -11,3 +11,5 @@ 'use strict' | ||
exports['test spread'] = require('./spread'); | ||
exports['test allResolved'] = require("./all-resolved"); | ||
exports['test node'] = require('./node'); | ||
exports['test bind'] = require('./bind'); | ||
@@ -14,0 +16,0 @@ exports['test GH issue 9'] = require('./issue/9'); |
var Q = require("../q"); | ||
Q | ||
.ref([1, 2, 3]) | ||
Q.resolve([1, 2, 3]) | ||
.map(function (n) { | ||
@@ -7,0 +6,0 @@ console.log('A', n); |
@@ -128,3 +128,3 @@ // vim:ts=4:sts=4:sw=4: | ||
Q.when(Q.del(d.promise, 'a'), function (result) { | ||
Q.when(Q.delete(d.promise, 'a'), function (result) { | ||
ASSERT.ok(result, 'delete returned `true`'); | ||
@@ -150,3 +150,2 @@ ASSERT.ok(!('a' in value), 'property was deleted'); | ||
}); | ||
d.resolve(); | ||
@@ -153,0 +152,0 @@ }; |
@@ -6,4 +6,4 @@ "use strict"; | ||
exports['test node'] = function (ASSERT, done) { | ||
var readFile = Q.node(FS.readFile); | ||
exports['test nbind (no arguments)'] = function (ASSERT, done) { | ||
var readFile = Q.nbind(FS.readFile); | ||
readFile(module.path || __filename, 'utf-8') | ||
@@ -19,16 +19,5 @@ .then(function (content) { | ||
exports['test ncall'] = function (ASSERT, done) { | ||
Q.ncall(FS.readFile, FS, module.path || __filename, 'utf-8') | ||
.then(function (content) { | ||
ASSERT.equal(typeof content, "string", "readFile content"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done) | ||
}; | ||
exports['test node bind'] = function (ASSERT, done) { | ||
exports['test nbind (thisp only)'] = function (ASSERT, done) { | ||
var that = {}; | ||
var artificial = Q.node(function (callback) { | ||
var artificial = Q.nbind(function (callback) { | ||
callback(void 0, this); | ||
@@ -46,4 +35,4 @@ }, that); | ||
exports['test node bind partial apply'] = function (ASSERT, done) { | ||
var artificial = Q.node(function (value, callback) { | ||
exports['test nbind (thisp plus arguments)'] = function (ASSERT, done) { | ||
var artificial = Q.nbind(function (value, callback) { | ||
callback(void 0, value); | ||
@@ -61,4 +50,4 @@ }, void 0, 10); | ||
exports['test node error'] = function (ASSERT, done) { | ||
var artificial = Q.node(function (callback) { | ||
exports['test nbind error'] = function (ASSERT, done) { | ||
var artificial = Q.nbind(function (callback) { | ||
callback(new Error("bad")); | ||
@@ -76,2 +65,24 @@ }); | ||
exports['test ncall'] = function (ASSERT, done) { | ||
Q.ncall(FS.readFile, FS, module.path || __filename, 'utf-8') | ||
.then(function (content) { | ||
ASSERT.equal(typeof content, "string", "readFile content"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done) | ||
}; | ||
exports['test napply'] = function (ASSERT, done) { | ||
Q.napply(FS.readFile, FS, [module.path || __filename, 'utf-8']) | ||
.then(function (content) { | ||
ASSERT.equal(typeof content, "string", "readFile content"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done) | ||
}; | ||
if (module == require.main) { | ||
@@ -78,0 +89,0 @@ require('test').run(exports); |
@@ -114,2 +114,7 @@ 'use strict' | ||
exports['test isPromise true'] = function (assert) { | ||
assert.ok(!Q.isPromise(true), 'true is not a promise') | ||
assert.ok(!Q.isPromise(false), 'false is not a promise') | ||
} | ||
if (module == require.main) require('test').run(exports) |
Sorry, the diff of this file is not supported yet
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
170315
0
58
3755
2
632
- Removedevent-queue@0.2.0
- Removedevent-queue@0.2.0(transitive)