Comparing version 0.8.4 to 0.8.5
@@ -11,3 +11,24 @@ <!-- vim:ts=4:sts=4:sw=4:et:tw=60 --> | ||
removed. Use ``deferred.makeNodeResolver()``. | ||
- WARNING: The deprecated ``call``, ``apply``, and ``bind`` are | ||
replaced with ``fcall``, ``fapply``, and ``fbind``. Use of a | ||
``thisp`` is discouraged. For calling methods, use ``post`` or | ||
``invoke``. | ||
- WARNING: The undocumented ``view`` and ``viewInfo`` will be removed. | ||
## 0.8.5 | ||
- Added preliminary support for long traces (@domenic) | ||
- Added ``fapply``, ``fcall``, ``fbind`` for non-thisp | ||
promised function calls. | ||
- Added ``return`` for async generators, where generators | ||
are implemented. | ||
- Rejected promises now have an "exception" property. If an object | ||
isRejected(object), then object.valueOf().exception will | ||
be the wrapped error. | ||
- Added Jasmine specifications | ||
- Support Internet Explorers 7–9 (with multiple bug fixes @domenic) | ||
- Support Firefox 12 | ||
- Support Safari 5.1.5 | ||
- Support Chrome 18 | ||
## 0.8.4 | ||
@@ -14,0 +35,0 @@ |
@@ -6,3 +6,3 @@ | ||
Q now has an ``async`` function. This can be used to | ||
Q has an ``async`` function. This can be used to | ||
decorate a generator function such that ``yield`` is | ||
@@ -12,5 +12,5 @@ effectively equivalent to ``await`` or ``defer`` syntax as | ||
Generator functions are presently only supported by | ||
SpiderMonkey, but they are standards track, and very similar | ||
down to details to generators in Python. | ||
Generator functions are presently only supported by SpiderMonkey, but | ||
they are (with some changes) on standards track, and very similar down | ||
to details to generators in Python. | ||
@@ -17,0 +17,0 @@ function count() { |
{ | ||
"name": "q", | ||
"version": "0.8.4", | ||
"version": "0.8.5", | ||
"description": "A library for promises (CommonJS/Promises/A,B,D)", | ||
@@ -5,0 +5,0 @@ "homepage": "http://github.com/kriskowal/q/", |
798
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 */ | ||
curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true, | ||
undef: true */ | ||
/*global define: false, Q: true, msSetImmediate: true, setImmediate: true, | ||
MessageChannel: true, ReturnValue: true, cajaVM: true, ses: true */ | ||
/*! | ||
* | ||
* Copyright 2009-2012 Kris Kowal under the terms of the MIT | ||
* license found at http://github.com/kriskowal/q/raw/master/LICENSE | ||
* | ||
* With parts by Tyler Close | ||
* Copyright 2007-2009 Tyler Close under the terms of the MIT X license found | ||
@@ -12,5 +17,44 @@ * at http://www.opensource.org/licenses/mit-license.html | ||
* | ||
* Copyright 2009-2011 Kris Kowal under the terms of the MIT | ||
* license found at http://github.com/kriskowal/q/raw/master/LICENSE | ||
* With parts by Mark Miller | ||
* Copyright (C) 2011 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* With formatStackTrace and formatSourcePosition functions | ||
* Copyright 2006-2008 the V8 project authors. All rights reserved. | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following | ||
* disclaimer in the documentation and/or other materials provided | ||
* with the distribution. | ||
* * Neither the name of Google Inc. nor the names of its | ||
* contributors may be used to endorse or promote products derived | ||
* from this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
@@ -27,14 +71,44 @@ | ||
if (typeof define === "function") { | ||
define(["exports"], definition); | ||
define(definition); | ||
// CommonJS | ||
} else if (typeof exports === "object") { | ||
definition(exports); | ||
definition(void 0, exports); | ||
// SES (Secure EcmaScript) | ||
} else if (typeof ses !== "undefined") { | ||
if (!ses.ok()) { | ||
return; | ||
} else { | ||
ses.makeQ = function () { | ||
var Q = {}; | ||
return definition(void 0, Q); | ||
}; | ||
} | ||
// <script> | ||
} else { | ||
definition(Q = {}); | ||
definition(void 0, Q = {}); | ||
} | ||
})(function (exports) { | ||
})(function (require, exports) { | ||
"use strict"; | ||
// shims | ||
// used for fallback "defend" and in "allResolved" | ||
var noop = function () {}; | ||
// for the security conscious, defend may be a deep freeze as provided | ||
// by cajaVM. Otherwise we try to provide a shallow freeze just to | ||
// discourage promise changes that are not compatible with secure | ||
// usage. If Object.freeze does not exist, fall back to doing nothing | ||
// (no op). | ||
var defend = Object.freeze || noop; | ||
if (typeof cajaVM !== "undefined") { | ||
defend = cajaVM.def; | ||
} | ||
// use the fastest possible means to execute a task in a future turn | ||
// of the event loop. | ||
var nextTick; | ||
@@ -46,3 +120,4 @@ if (typeof process !== "undefined") { | ||
// IE 10 only, at the moment | ||
nextTick = msSetImmediate; | ||
// And yes, ``bind``ing to ``window`` is necessary O_o. | ||
nextTick = msSetImmediate.bind(window); | ||
} else if (typeof setImmediate === "function") { | ||
@@ -60,3 +135,3 @@ // https://github.com/NobleJS/setImmediate | ||
var task = head.task; | ||
head.task = null; | ||
delete head.task; | ||
task(); | ||
@@ -75,22 +150,88 @@ }; | ||
// useful for an identity stub and default resolvers | ||
function identity(x) { return x; } | ||
// Attempt to make generics safe in the face of downstream | ||
// modifications. | ||
// There is no situation where this is necessary. | ||
// If you need a security guarantee, these primordials need to be | ||
// deeply frozen anyway, and if you don’t need a security guarantee, | ||
// this is just plain paranoid. | ||
// However, this does have the nice side-effect of reducing the size | ||
// of the code by reducing x.call() to merely x(), eliminating many | ||
// hard-to-minify characters. | ||
// See Mark Miller’s explanation of what this does. | ||
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming | ||
var uncurryThis; | ||
// I have kept both variations because the first is theoretically | ||
// faster, if bind is available. | ||
if (Function.prototype.bind) { | ||
var Function_bind = Function.prototype.bind; | ||
uncurryThis = Function_bind.bind(Function_bind.call); | ||
} else { | ||
uncurryThis = function (f) { | ||
return function (thisp) { | ||
return f.call.apply(f, arguments); | ||
}; | ||
}; | ||
} | ||
// shims | ||
function shim(object, name, shimmed) { | ||
if (!object[name]) { | ||
object[name] = shimmed; | ||
var array_slice = uncurryThis(Array.prototype.slice); | ||
var array_reduce = uncurryThis( | ||
Array.prototype.reduce || function (callback, basis) { | ||
var index = 0, | ||
length = this.length; | ||
// concerning the initial value, if one is not provided | ||
if (arguments.length === 1) { | ||
// seek to the first value in the array, accounting | ||
// for the possibility that is is a sparse array | ||
do { | ||
if (index in this) { | ||
basis = this[index++]; | ||
break; | ||
} | ||
if (++index >= length) { | ||
throw new TypeError(); | ||
} | ||
} while (1); | ||
} | ||
// reduce | ||
for (; index < length; index++) { | ||
// account for the possibility that the array is sparse | ||
if (index in this) { | ||
basis = callback(basis, this[index], index); | ||
} | ||
} | ||
return basis; | ||
} | ||
return object[name]; | ||
} | ||
); | ||
var freeze = shim(Object, "freeze", identity); | ||
var array_indexOf = uncurryThis( | ||
Array.prototype.indexOf || function (value) { | ||
// not a very good shim, but good enough for our one use of it | ||
for (var i = 0; i < this.length; i++) { | ||
if (this[i] === value) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
); | ||
var create = shim(Object, "create", function (prototype) { | ||
var array_map = uncurryThis( | ||
Array.prototype.map || function (callback, thisp) { | ||
var self = this; | ||
var collect = []; | ||
array_reduce(self, function (undefined, value, index) { | ||
collect.push(callback.call(thisp, value, index, self)); | ||
}, void 0); | ||
return collect; | ||
} | ||
); | ||
var object_create = Object.create || function (prototype) { | ||
function Type() { } | ||
Type.prototype = prototype; | ||
return new Type(); | ||
}); | ||
}; | ||
var keys = shim(Object, "keys", function (object) { | ||
var object_keys = Object.keys || function (object) { | ||
var keys = []; | ||
@@ -101,47 +242,173 @@ for (var key in object) { | ||
return keys; | ||
}); | ||
}; | ||
var reduce = Array.prototype.reduce || function (callback, basis) { | ||
var i = 0, | ||
ii = this.length; | ||
// concerning the initial value, if one is not provided | ||
if (arguments.length === 1) { | ||
// seek to the first value in the array, accounting | ||
// for the possibility that is is a sparse array | ||
do { | ||
if (i in this) { | ||
basis = this[i++]; | ||
break; | ||
var object_toString = Object.prototype.toString; | ||
// generator related shims | ||
function isStopIteration(exception) { | ||
return ( | ||
object_toString(exception) === "[object StopIteration]" || | ||
exception instanceof QReturnValue | ||
); | ||
} | ||
var QReturnValue; | ||
if (typeof ReturnValue !== "undefined") { | ||
QReturnValue = ReturnValue; | ||
} else { | ||
QReturnValue = function (value) { | ||
this.value = value; | ||
}; | ||
} | ||
// long stack traces | ||
function formatStackTrace(error, frames) { | ||
var lines = []; | ||
try { | ||
lines.push(error.toString()); | ||
} catch (e) { | ||
try { | ||
lines.push("<error: " + e + ">"); | ||
} catch (ee) { | ||
lines.push("<error>"); | ||
} | ||
} | ||
for (var i = 0; i < frames.length; i++) { | ||
var frame = frames[i]; | ||
var line; | ||
// <Inserted by @domenic> | ||
if (typeof frame === "string") { | ||
lines.push(frame); | ||
// </Inserted by @domenic> | ||
} else { | ||
try { | ||
line = formatSourcePosition(frame); | ||
} catch (e) { | ||
try { | ||
line = "<error: " + e + ">"; | ||
} catch (ee) { | ||
// Any code that reaches this point is seriously nasty! | ||
line = "<error>"; | ||
} | ||
} | ||
if (++i >= ii) { | ||
throw new TypeError(); | ||
lines.push(" at " + line); | ||
} | ||
} | ||
return lines.join("\n"); | ||
} | ||
function formatSourcePosition(frame) { | ||
var fileLocation = ""; | ||
if (frame.isNative()) { | ||
fileLocation = "native"; | ||
} else if (frame.isEval()) { | ||
fileLocation = "eval at " + frame.getEvalOrigin(); | ||
} else { | ||
var fileName = frame.getFileName(); | ||
if (fileName) { | ||
fileLocation += fileName; | ||
var lineNumber = frame.getLineNumber(); | ||
if (lineNumber !== null) { | ||
fileLocation += ":" + lineNumber; | ||
var columnNumber = frame.getColumnNumber(); | ||
if (columnNumber) { | ||
fileLocation += ":" + columnNumber; | ||
} | ||
} | ||
} while (1); | ||
} | ||
} | ||
// reduce | ||
for (; i < ii; i++) { | ||
// account for the possibility that the array is sparse | ||
if (i in this) { | ||
basis = callback(basis, this[i], i); | ||
if (!fileLocation) { | ||
fileLocation = "unknown source"; | ||
} | ||
var line = ""; | ||
var functionName = frame.getFunction().name; | ||
var addPrefix = true; | ||
var isConstructor = frame.isConstructor(); | ||
var isMethodCall = !(frame.isToplevel() || isConstructor); | ||
if (isMethodCall) { | ||
var methodName = frame.getMethodName(); | ||
line += frame.getTypeName() + "."; | ||
if (functionName) { | ||
line += functionName; | ||
if (methodName && (methodName !== functionName)) { | ||
line += " [as " + methodName + "]"; | ||
} | ||
} else { | ||
line += methodName || "<anonymous>"; | ||
} | ||
} else if (isConstructor) { | ||
line += "new " + (functionName || "<anonymous>"); | ||
} else if (functionName) { | ||
line += functionName; | ||
} else { | ||
line += fileLocation; | ||
addPrefix = false; | ||
} | ||
return basis; | ||
}; | ||
if (addPrefix) { | ||
line += " (" + fileLocation + ")"; | ||
} | ||
return line; | ||
} | ||
function isStopIteration(exception) { | ||
return Object.prototype.toString.call(exception) === | ||
"[object StopIteration]"; | ||
/* | ||
* Retrieves an array of structured stack frames parsed from the ``stack`` | ||
* property of a given object. | ||
* | ||
* @param objectWithStack {Object} an object with a ``stack`` property: usually | ||
* an error or promise. | ||
* | ||
* @returns an array of stack frame objects. For more information, see | ||
* [V8's JavaScript stack trace API documentation](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi). | ||
*/ | ||
function getStackFrames(objectWithStack) { | ||
var oldPrepareStackTrace = Error.prepareStackTrace; | ||
Error.prepareStackTrace = function (error, frames) { | ||
// Filter out frames from the innards of Node and Q. | ||
return frames.filter(function (frame) { | ||
var fileName = frame.getFileName(); | ||
return ( | ||
fileName !== "module.js" && | ||
fileName !== "node.js" && | ||
fileName !== qFileName | ||
); | ||
}); | ||
}; | ||
var stack = objectWithStack.stack; | ||
Error.prepareStackTrace = oldPrepareStackTrace; | ||
return stack; | ||
} | ||
// Abbreviations for performance and minification | ||
var slice = Array.prototype.slice; | ||
function valueOf(value) { | ||
// if !Object.isObject(value) | ||
if (Object(value) !== value) { | ||
return value; | ||
} else { | ||
return value.valueOf(); | ||
} | ||
// discover own file name for filtering stack traces | ||
var qFileName; | ||
if (Error.captureStackTrace) { | ||
qFileName = (function () { | ||
var fileName; | ||
var oldPrepareStackTrace = Error.prepareStackTrace; | ||
Error.prepareStackTrace = function (error, frames) { | ||
fileName = frames[0].getFileName(); | ||
}; | ||
// teases call of temporary prepareStackTrace | ||
// JSHint and Closure Compiler generate known warnings here | ||
new Error().stack; | ||
Error.prepareStackTrace = oldPrepareStackTrace; | ||
return fileName; | ||
})(); | ||
} | ||
// end of shims | ||
// beginning of real work | ||
/** | ||
@@ -163,3 +430,2 @@ * Performs a task in a future turn of the event loop. | ||
exports.defer = defer; | ||
function defer() { | ||
@@ -174,7 +440,7 @@ // if "pending" is an "Array", that indicates that the promise has not yet | ||
var deferred = create(defer.prototype); | ||
var promise = create(makePromise.prototype); | ||
var deferred = object_create(defer.prototype); | ||
var promise = object_create(makePromise.prototype); | ||
promise.promiseSend = function () { | ||
var args = slice.call(arguments); | ||
var args = array_slice(arguments); | ||
if (pending) { | ||
@@ -196,2 +462,6 @@ pending.push(args); | ||
if (Error.captureStackTrace) { | ||
Error.captureStackTrace(promise, defer); | ||
} | ||
function become(resolvedValue) { | ||
@@ -202,3 +472,3 @@ if (!pending) { | ||
value = resolve(resolvedValue); | ||
reduce.call(pending, function (undefined, pending) { | ||
array_reduce(pending, function (undefined, pending) { | ||
nextTick(function () { | ||
@@ -212,3 +482,5 @@ value.promiseSend.apply(value, pending); | ||
deferred.promise = freeze(promise); | ||
defend(promise); | ||
deferred.promise = promise; | ||
deferred.resolve = become; | ||
@@ -222,2 +494,7 @@ deferred.reject = function (exception) { | ||
/** | ||
* Creates a Node-style callback that will resolve or reject the deferred | ||
* promise. | ||
* @returns a nodeback | ||
*/ | ||
defer.prototype.node = // XXX deprecated | ||
@@ -230,3 +507,3 @@ defer.prototype.makeNodeResolver = function () { | ||
} else if (arguments.length > 2) { | ||
self.resolve(Array.prototype.slice.call(arguments, 1)); | ||
self.resolve(array_slice(arguments, 1)); | ||
} else { | ||
@@ -238,2 +515,8 @@ self.resolve(value); | ||
/** | ||
* @param makePromise {Function} a function that returns nothing and accepts | ||
* the resolve and reject functions for a deferred. | ||
* @returns a promise that may be resolved with the given resolve and reject | ||
* functions, or rejected by a thrown exception in makePromise | ||
*/ | ||
exports.promise = promise; | ||
@@ -246,4 +529,3 @@ function promise(makePromise) { | ||
deferred.resolve, | ||
deferred.reject, | ||
deferred.progress | ||
deferred.reject | ||
).fail(deferred.reject); | ||
@@ -265,13 +547,13 @@ return deferred.promise; | ||
exports.makePromise = makePromise; | ||
function makePromise(descriptor, fallback, valueOf, rejected) { | ||
function makePromise(descriptor, fallback, valueOf, exception) { | ||
if (fallback === void 0) { | ||
fallback = function (op) { | ||
return reject("Promise does not support operation: " + op); | ||
return reject(new Error("Promise does not support operation: " + op)); | ||
}; | ||
} | ||
var promise = create(makePromise.prototype); | ||
var promise = object_create(makePromise.prototype); | ||
promise.promiseSend = function (op, resolved /* ...args */) { | ||
var args = slice.call(arguments, 2); | ||
var args = array_slice(arguments, 2); | ||
var result; | ||
@@ -287,3 +569,3 @@ try { | ||
} | ||
return (resolved || identity)(result); | ||
resolved(result); | ||
}; | ||
@@ -295,7 +577,9 @@ | ||
if (rejected) { | ||
promise.promiseRejected = true; | ||
if (exception) { | ||
promise.exception = exception; | ||
} | ||
return freeze(promise); | ||
defend(promise); | ||
return promise; | ||
} | ||
@@ -309,3 +593,3 @@ | ||
// Chainable methods | ||
reduce.call( | ||
array_reduce( | ||
[ | ||
@@ -318,2 +602,3 @@ "isResolved", "isFulfilled", "isRejected", | ||
"apply", "call", "bind", | ||
"fapply", "fcall", "fbind", | ||
"all", "allResolved", | ||
@@ -328,3 +613,3 @@ "view", "viewInfo", | ||
exports, | ||
[this].concat(slice.call(arguments)) | ||
[this].concat(array_slice(arguments)) | ||
); | ||
@@ -341,8 +626,28 @@ }; | ||
makePromise.prototype.toString = function () { | ||
return '[object Promise]'; | ||
return "[object Promise]"; | ||
}; | ||
freeze(makePromise.prototype); | ||
defend(makePromise.prototype); | ||
/** | ||
* If an object is not a promise, it is as "near" as possible. | ||
* If a promise is rejected, it is as "near" as possible too. | ||
* If it’s a fulfilled promise, the fulfillment value is nearer. | ||
* If it’s a deferred promise and the deferred has been resolved, the | ||
* resolution is "nearer". | ||
* @param object | ||
* @returns most resolved (nearest) form of the object | ||
*/ | ||
exports.nearer = valueOf; | ||
function valueOf(value) { | ||
// if !Object.isObject(value) | ||
// generates a known JSHint "constructor invocation without new" warning | ||
if (Object(value) !== value) { | ||
return value; | ||
} else { | ||
return value.valueOf(); | ||
} | ||
} | ||
/** | ||
* @returns whether the given object is a promise. | ||
@@ -379,3 +684,3 @@ * Otherwise it is a fulfilled value. | ||
object = valueOf(object); | ||
return object && !!object.promiseRejected; | ||
return isPromise(object) && 'exception' in object; | ||
} | ||
@@ -385,3 +690,3 @@ | ||
var errors = []; | ||
if (typeof window !== "undefined") { | ||
if (typeof window !== "undefined" && window.console) { | ||
// This promise library consumes exceptions thrown in handlers so | ||
@@ -400,2 +705,3 @@ // they can be handled by a subsequent promise. The rejected | ||
function reject(exception) { | ||
exception = exception || new Error(); | ||
var rejection = makePromise({ | ||
@@ -405,3 +711,3 @@ "when": function (rejected) { | ||
if (rejected) { | ||
var at = rejections.indexOf(this); | ||
var at = array_indexOf(rejections, this); | ||
if (at !== -1) { | ||
@@ -417,4 +723,4 @@ errors.splice(at, 1); | ||
}, function valueOf() { | ||
return reject(exception); | ||
}, true); | ||
return this; | ||
}, exception); | ||
// note that the error has not been handled | ||
@@ -430,5 +736,5 @@ rejections.push(rejection); | ||
*/ | ||
exports.begin = resolve; | ||
exports.begin = resolve; // XXX experimental | ||
exports.resolve = resolve; | ||
exports.ref = resolve; // XXX deprecated | ||
exports.ref = resolve; // XXX deprecated, use resolve | ||
function resolve(object) { | ||
@@ -466,2 +772,5 @@ // If the object is already a Promise, return it directly. This enables | ||
}, | ||
"fapply": function (args) { | ||
return object.apply(void 0, args); | ||
}, | ||
"viewInfo": function () { | ||
@@ -487,3 +796,3 @@ var on = object; | ||
"keys": function () { | ||
return keys(object); | ||
return object_keys(object); | ||
} | ||
@@ -501,3 +810,3 @@ }, void 0, function valueOf() { | ||
* @returns promise a wrapping of that object that | ||
* additionally responds to the 'isDef' message | ||
* additionally responds to the "isDef" message | ||
* without a rejection. | ||
@@ -510,3 +819,3 @@ */ | ||
}, function fallback(op) { | ||
var args = slice.call(arguments); | ||
var args = array_slice(arguments); | ||
return send.apply(void 0, [object].concat(args)); | ||
@@ -527,3 +836,3 @@ }, function () { | ||
}, function fallback(op) { | ||
var args = slice.call(arguments); | ||
var args = array_slice(arguments); | ||
return send.apply(void 0, [object].concat(args)); | ||
@@ -550,3 +859,3 @@ }, function () { | ||
var properties = info.properties || {}; | ||
Object.keys(properties).forEach(function (name) { | ||
object_keys(properties).forEach(function (name) { | ||
if (properties[name] === "function") { | ||
@@ -594,4 +903,4 @@ view[name] = function () { | ||
return rejected ? rejected(exception) : reject(exception); | ||
} catch (exception) { | ||
return reject(exception); | ||
} catch (newException) { | ||
return reject(newException); | ||
} | ||
@@ -606,6 +915,7 @@ } | ||
done = true; | ||
deferred.resolve( | ||
resolve(value) | ||
.promiseSend("when", _fulfilled, _rejected) | ||
); | ||
resolve(value).promiseSend("when", function (value) { | ||
deferred.resolve(_fulfilled(value)); | ||
}, function (exception) { | ||
deferred.resolve(_rejected(exception)); | ||
}); | ||
}, function (exception) { | ||
@@ -623,2 +933,12 @@ if (done) { | ||
/** | ||
* Spreads the values of a promised array of arguments into the | ||
* fulfillment callback. | ||
* @param fulfilled callback that receives variadic arguments from the | ||
* promised array | ||
* @param rejected callback that receives the exception if the promise | ||
* is rejected. | ||
* @returns a promise for the return value or thrown exception of | ||
* either callback. | ||
*/ | ||
exports.spread = spread; | ||
@@ -690,12 +1010,28 @@ function spread(promise, fulfilled, rejected) { | ||
/** | ||
* Throws a ReturnValue exception to stop an asynchronous generator. | ||
* Only useful presently in Firefox/SpiderMonkey since generators are | ||
* implemented. | ||
* @param value the return value for the surrounding generator | ||
* @throws ReturnValue exception with the value. | ||
* @example | ||
* Q.async(function () { | ||
* var foo = yield getFooPromise(); | ||
* var bar = yield getBarPromise(); | ||
* Q.return(foo + bar); | ||
* }) | ||
*/ | ||
exports['return'] = _return; | ||
function _return(value) { | ||
throw new QReturnValue(value); | ||
} | ||
/** | ||
* Constructs a promise method that can be used to safely observe resolution of | ||
* a promise for an arbitrarily named method like "propfind" in a future turn. | ||
* | ||
* "sender" constructs methods like "get(promise, name)" and "put(promise)". | ||
*/ | ||
exports.sender = sender; | ||
exports.Method = sender; // XXX deprecated | ||
exports.sender = sender; // XXX deprecated, use dispatcher | ||
exports.Method = sender; // XXX deprecated, use dispatcher | ||
function sender(op) { | ||
return function (object) { | ||
var args = slice.call(arguments, 1); | ||
var args = array_slice(arguments, 1); | ||
return send.apply(void 0, [object, op].concat(args)); | ||
@@ -712,6 +1048,6 @@ }; | ||
*/ | ||
exports.send = send; | ||
exports.send = send; // XXX deprecated, use dispatch | ||
function send(object, op) { | ||
var deferred = defer(); | ||
var args = slice.call(arguments, 2); | ||
var args = array_slice(arguments, 2); | ||
object = resolve(object); | ||
@@ -728,2 +1064,36 @@ nextTick(function () { | ||
/** | ||
* sends a message to a value in a future turn | ||
* @param object* the recipient | ||
* @param op the name of the message operation, e.g., "when", | ||
* @param args further arguments to be forwarded to the operation | ||
* @returns result {Promise} a promise for the result of the operation | ||
*/ | ||
exports.dispatch = dispatch; | ||
function dispatch(object, op, args) { | ||
var deferred = defer(); | ||
object = resolve(object); | ||
nextTick(function () { | ||
object.promiseSend.apply( | ||
object, | ||
[op, deferred.resolve].concat(args) | ||
); | ||
}); | ||
return deferred.promise; | ||
} | ||
/** | ||
* Constructs a promise method that can be used to safely observe resolution of | ||
* a promise for an arbitrarily named method like "propfind" in a future turn. | ||
* | ||
* "dispatcher" constructs methods like "get(promise, name)" and "put(promise)". | ||
*/ | ||
exports.dispatcher = dispatcher; | ||
function dispatcher(op) { | ||
return function (object) { | ||
var args = array_slice(arguments, 1); | ||
return dispatch(object, op, args); | ||
}; | ||
} | ||
/** | ||
* Gets the value of a property in a future turn. | ||
@@ -734,3 +1104,3 @@ * @param object promise or immediate reference for target object | ||
*/ | ||
exports.get = sender("get"); | ||
exports.get = dispatcher("get"); | ||
@@ -744,3 +1114,3 @@ /** | ||
*/ | ||
exports.put = sender("put"); | ||
exports.put = dispatcher("put"); | ||
@@ -753,3 +1123,4 @@ /** | ||
*/ | ||
exports.del = exports['delete'] = sender("del"); | ||
exports["delete"] = // XXX experimental | ||
exports.del = dispatcher("del"); | ||
@@ -768,3 +1139,4 @@ /** | ||
*/ | ||
var post = exports.post = sender("post"); | ||
// bound locally because it is used by other methods | ||
var post = exports.post = dispatcher("post"); | ||
@@ -779,3 +1151,3 @@ /** | ||
exports.invoke = function (value, name) { | ||
var args = slice.call(arguments, 2); | ||
var args = array_slice(arguments, 2); | ||
return post(value, name, args); | ||
@@ -787,50 +1159,66 @@ }; | ||
* @param object promise or immediate reference for target function | ||
* @param context the context object (this) for the call | ||
* @param thisp the `this` object for the call | ||
* @param args array of application arguments | ||
*/ | ||
var apply = exports.apply = sender("apply"); | ||
var apply = exports.apply = dispatcher("apply"); // XXX deprecated, use fapply | ||
/** | ||
* Applies the promised function in a future turn. | ||
* @param object promise or immediate reference for target function | ||
* @param args array of application arguments | ||
*/ | ||
var fapply = exports.fapply = dispatcher("fapply"); | ||
/** | ||
* Calls the promised function in a future turn. | ||
* @param object promise or immediate reference for target function | ||
* @param context the context object (this) for the call | ||
* @param thisp the `this` object for the call | ||
* @param ...args array of application arguments | ||
*/ | ||
exports.call = exports['try'] = call; | ||
function call(value, context) { | ||
var args = slice.call(arguments, 2); | ||
return apply(value, context, args); | ||
exports.call = call; // XXX deprecated, use fcall | ||
function call(value, thisp) { | ||
var args = array_slice(arguments, 2); | ||
return apply(value, thisp, args); | ||
} | ||
/** | ||
* Calls the promised function in a future turn. | ||
* @param object promise or immediate reference for target function | ||
* @param ...args array of application arguments | ||
*/ | ||
exports["try"] = fcall; // XXX experimental | ||
exports.fcall = fcall; | ||
function fcall(value) { | ||
var args = array_slice(arguments, 1); | ||
return fapply(value, 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 thisp the `this` object for the call | ||
* @param ...args array of application arguments | ||
*/ | ||
exports.bind = bind; | ||
function bind(value, context) { | ||
var args = slice.call(arguments, 2); | ||
exports.bind = bind; // XXX deprecated, use fbind | ||
function bind(value, thisp) { | ||
var args = array_slice(arguments, 2); | ||
return function bound() { | ||
var allArgs = args.concat(slice.call(arguments)); | ||
var allArgs = args.concat(array_slice(arguments)); | ||
return apply(value, thisp, allArgs); | ||
}; | ||
} | ||
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); | ||
} | ||
/** | ||
* 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 ...args array of application arguments | ||
*/ | ||
exports.fbind = fbind; | ||
function fbind(value) { | ||
var args = array_slice(arguments, 1); | ||
return function fbound() { | ||
var allArgs = args.concat(array_slice(arguments)); | ||
return fapply(value, allArgs); | ||
}; | ||
@@ -845,3 +1233,3 @@ } | ||
*/ | ||
exports.keys = sender("keys"); | ||
exports.keys = dispatcher("keys"); | ||
@@ -865,3 +1253,3 @@ /** | ||
var deferred = defer(); | ||
reduce.call(promises, function (undefined, promise, index) { | ||
array_reduce(promises, function (undefined, promise, index) { | ||
when(promise, function (value) { | ||
@@ -879,9 +1267,18 @@ promises[index] = value; | ||
/** | ||
* Waits for all promises to be resolved, either fulfilled or | ||
* rejected. This is distinct from `all` since that would stop | ||
* waiting at the first rejection. The promise returned by | ||
* `allResolved` will never be rejected. | ||
* @param promises a promise for an array (or an array) of promises | ||
* (or values) | ||
* @return a promise for an array of promises | ||
*/ | ||
exports.allResolved = allResolved; | ||
function allResolved(promises) { | ||
return when(promises, function (promises) { | ||
return when(all(promises.map(function (promise) { | ||
return when(promise, identity, identity); | ||
return when(all(array_map(promises, function (promise) { | ||
return when(promise, noop, noop); | ||
})), function () { | ||
return promises.map(resolve); | ||
return array_map(promises, resolve); | ||
}); | ||
@@ -900,3 +1297,3 @@ }); | ||
*/ | ||
exports['catch'] = | ||
exports["catch"] = // XXX experimental | ||
exports.fail = fail; | ||
@@ -918,3 +1315,3 @@ function fail(promise, rejected) { | ||
*/ | ||
exports['finally'] = | ||
exports["finally"] = // XXX experimental | ||
exports.fin = fin; | ||
@@ -939,3 +1336,3 @@ function fin(promise, callback) { | ||
*/ | ||
exports.end = end; | ||
exports.end = end; // XXX stopgap | ||
function end(promise) { | ||
@@ -946,2 +1343,16 @@ when(promise, void 0, function (error) { | ||
nextTick(function () { | ||
// If possible (that is, if in V8), transform the error stack | ||
// trace by removing Node and Q cruft, then concatenating with | ||
// the stack trace of the promise we are ``end``ing. See #57. | ||
if (Error.captureStackTrace) { | ||
var errorStackFrames = getStackFrames(error); | ||
var promiseStackFrames = getStackFrames(promise); | ||
var combinedStackFrames = errorStackFrames.concat( | ||
"From previous event:", | ||
promiseStackFrames | ||
); | ||
error.stack = formatStackTrace(error, combinedStackFrames); | ||
} | ||
throw error; | ||
@@ -992,2 +1403,33 @@ }); | ||
/** | ||
* 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.napply(FS.readFile, FS, [__filename]) | ||
* .then(function (content) { | ||
* }) | ||
* | ||
*/ | ||
exports.napply = napply; | ||
function napply(callback, thisp, args) { | ||
return nbind(callback, thisp).apply(void 0, 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 = array_slice(arguments, 2); | ||
return napply(callback, thisp, args); | ||
} | ||
/** | ||
* Wraps a NodeJS continuation passing function and returns an equivalent | ||
@@ -1002,15 +1444,20 @@ * version that returns a promise. | ||
exports.nbind = nbind; | ||
exports.node = nbind; // XXX deprecated | ||
function nbind(callback /* thisp, ...args*/) { | ||
if (arguments.length > 1) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
callback = callback.bind.apply(callback, args); | ||
var thisp = arguments[1]; | ||
var args = array_slice(arguments, 2); | ||
var originalCallback = callback; | ||
callback = function () { | ||
var combinedArgs = args.concat(array_slice(arguments)); | ||
return originalCallback.apply(thisp, combinedArgs); | ||
}; | ||
} | ||
return function () { | ||
var deferred = defer(); | ||
var args = slice.call(arguments); | ||
var args = array_slice(arguments); | ||
// add a continuation that resolves the promise | ||
args.push(deferred.node()); | ||
args.push(deferred.makeNodeResolver()); | ||
// trap exceptions thrown by the callback | ||
apply(callback, this, args) | ||
fapply(callback, args) | ||
.fail(deferred.reject); | ||
@@ -1022,32 +1469,33 @@ return deferred.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.napply(FS.readFile, FS, [__filename]) | ||
* .then(function (content) { | ||
* }) | ||
* | ||
* Calls a method of a Node-style object that accepts a Node-style | ||
* callback with a given array of arguments, plus a provided callback. | ||
* @param object an object that has the named method | ||
* @param {String} name name of the method of object | ||
* @param {Array} args arguments to pass to the method; the callback | ||
* will be provided by Q and appended to these arguments. | ||
* @returns a promise for the value or error | ||
*/ | ||
exports.napply = napply; | ||
function napply(callback, thisp, args) { | ||
return nbind(callback).apply(thisp, args); | ||
exports.npost = npost; | ||
function npost(object, name, args) { | ||
return napply(object[name], name, 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) { | ||
* }) | ||
* | ||
* Calls a method of a Node-style object that accepts a Node-style | ||
* callback, forwarding the given variadic arguments, plus a provided | ||
* callback argument. | ||
* @param object an object that has the named method | ||
* @param {String} name name of the method of object | ||
* @param ...args arguments to pass to the method; the callback will | ||
* be provided by Q and appended to these arguments. | ||
* @returns a promise for the value or error | ||
*/ | ||
exports.ncall = ncall; | ||
function ncall(callback, thisp /*, ...args*/) { | ||
var args = slice.call(arguments, 2); | ||
return napply(callback, thisp, args); | ||
exports.ninvoke = ninvoke; | ||
function ninvoke(object, name /*, ...args*/) { | ||
var args = array_slice(arguments, 2); | ||
return napply(object[name], name, args); | ||
} | ||
defend(exports); | ||
}); |
@@ -32,3 +32,3 @@ [![Build Status](https://secure.travis-ci.org/kriskowal/q.png)](http://travis-ci.org/kriskowal/q) | ||
```javascript | ||
Q.call(step1) | ||
Q.fcall(step1) | ||
.then(step2) | ||
@@ -65,4 +65,4 @@ .then(step3) | ||
- a ``<script>`` tag (creating a ``Q`` global variable): only ~2 KB | ||
minified and gzipped! | ||
- a ``<script>`` tag (creating a ``Q`` global variable): | ||
~3.3 KB minified and gzipped. | ||
- a NodeJS and CommonJS module available from NPM as the ``q`` | ||
@@ -411,3 +411,3 @@ package | ||
```javascript | ||
return Q.call(function () { | ||
return Q.fcall(function () { | ||
return 10; | ||
@@ -420,3 +420,3 @@ }); | ||
```javascript | ||
return Q.call(function () { | ||
return Q.fcall(function () { | ||
throw new Error("Can't do it"); | ||
@@ -432,3 +432,3 @@ }) | ||
```javascript | ||
return Q.call(eventualAdd, null, 2, 2); | ||
return Q.fcall(eventualAdd, null, 2, 2); | ||
``` | ||
@@ -456,3 +456,3 @@ | ||
```javascript | ||
var rejection = Q.call(function () { | ||
var rejection = Q.fcall(function () { | ||
throw new Error("Can't do it"); | ||
@@ -511,3 +511,3 @@ }); | ||
```javascript | ||
return Q.call(function () { | ||
return Q.fcall(function () { | ||
return [a, b]; | ||
@@ -532,6 +532,6 @@ }) | ||
as provided by your library, you should wrap it using a Q function. | ||
You can even use ``Q.call`` as a shorthand. | ||
You can even use ``Q.invoke`` as a shorthand. | ||
```javascript | ||
return Q.call($.ajax, $, ...) | ||
return Q.invoke($, 'ajax', ...) | ||
.then(function () { | ||
@@ -557,6 +557,4 @@ }) | ||
value.foo(...args) promise.invoke("foo", ...args) | ||
value(...args) promise.apply(null, [args]) | ||
value(...args) promise.call(null, ...args) | ||
value.call(thisp, ...args) promise.apply(thisp, [args]) | ||
value.apply(thisp, [args]) promise.call(thisp, ...args) | ||
value(...args) promise.fapply([args]) | ||
value(...args) promise.fcall(...args) | ||
``` | ||
@@ -575,3 +573,3 @@ | ||
```javascript | ||
return Q.call(function () { | ||
return Q.fcall(function () { | ||
return [{ foo: "bar" }, { foo: "baz" }]; | ||
@@ -587,3 +585,3 @@ }) | ||
```javascript | ||
return Q.call(function () { | ||
return Q.fcall(function () { | ||
return [{ foo: "bar" }, { foo: "baz" }]; | ||
@@ -607,3 +605,4 @@ }) | ||
And there’s a ``Q.ncall`` function for shorter. | ||
And there are ``Q.ncall`` and ``Q.ninvoke`` for even shorter | ||
expression. | ||
@@ -614,2 +613,6 @@ ```javascript | ||
```javascript | ||
return Q.ninvoke(FS, 'readFile', "foo.txt", "utf-8"); | ||
``` | ||
There is also a ``Q.nbind`` function that that creates a reusable | ||
@@ -616,0 +619,0 @@ wrapper. |
@@ -115,88 +115,4 @@ "use strict"; | ||
exports['test invoking with new'] = function (ASSERT, done) { | ||
function Point(x, y) { | ||
this.x = x; | ||
this.y = y; | ||
} | ||
var BoundPoint = Q.bind(Point, null, 1); | ||
(new BoundPoint(2)) | ||
.then(function (point) { | ||
ASSERT.deepEqual(point, { x: 1, y: 2 }, "fulfilled with constructed"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}). | ||
fin(done); | ||
}; | ||
exports['test returns correctly when new\'ed'] = function (ASSERT, done) { | ||
var returned = {}; | ||
var bound = Q.bind(function () { return returned; }); | ||
(new bound()) | ||
.then(function (val) { | ||
ASSERT.strictEqual(val, returned, "fulfilled with correct value"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done); | ||
}; | ||
exports['test throwing when new\'ed'] = function (ASSERT, done) { | ||
var throwMe = new Error("boo!"); | ||
var bound = Q.bind(function () { | ||
throw throwMe; | ||
}); | ||
(new bound()) | ||
.then(function () { | ||
ASSERT.ok(false, "should not be fulfilled"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.strictEqual(reason, throwMe, "rejected with correct reason"); | ||
}) | ||
.fin(done); | ||
}; | ||
exports['test returns only objects when new\'ed'] = function (ASSERT, done) { | ||
var bound = Q.bind(function () { | ||
this.x = 1; | ||
return 5; | ||
}); | ||
(new bound()) | ||
.then(function (val) { | ||
ASSERT.deepEqual(val, { x: 1 }, "fulfilled with object not primitive"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done); | ||
}; | ||
exports['test returns only objects when new\'ed 2'] = function (ASSERT, done) { | ||
var bound = Q.bind(function () { | ||
this.x = 1; | ||
return Q.resolve(5); | ||
}); | ||
(new bound()) | ||
.then(function (val) { | ||
ASSERT.deepEqual(val, { x: 1 }, "fulfilled with object not primitive"); | ||
}) | ||
.fail(function (reason) { | ||
ASSERT.ok(false, reason); | ||
}) | ||
.fin(done); | ||
}; | ||
if (module == require.main) { | ||
require('test').run(exports); | ||
} |
@@ -6,3 +6,3 @@ "use strict"; | ||
exports['test spread'] = function (ASSERT, done) { | ||
Q.ref([1,2,3]) | ||
Q.resolve([1,2,3]) | ||
.spread(function (a, b, c) { | ||
@@ -21,3 +21,3 @@ ASSERT.equal(a, 1, 'spread 1'); | ||
exports['test spread all'] = function (ASSERT, done) { | ||
Q.ref([1,2,3].map(Q.ref)) | ||
Q.resolve([1,2,3].map(Q.resolve)) | ||
.all() | ||
@@ -24,0 +24,0 @@ .spread(function (a, b, c) { |
var Q = require('../q'); | ||
exports['test ref assimilation'] = function (ASSERT, done) { | ||
Q.ref({ | ||
exports['test resolve assimilation'] = function (ASSERT, done) { | ||
Q.resolve({ | ||
"then": function (resolved, rejected) { | ||
@@ -43,4 +43,4 @@ resolved(10); | ||
exports['test ref assimilation and piplining'] = function (ASSERT, done) { | ||
Q.ref({ | ||
exports['test resolve assimilation and piplining'] = function (ASSERT, done) { | ||
Q.resolve({ | ||
"then": function (resolved, rejected) { | ||
@@ -47,0 +47,0 @@ resolved([10]); |
@@ -21,4 +21,4 @@ | ||
exports['test ref undefined'] = function (ASSERT) { | ||
var r = Q.ref(); | ||
exports['test resolve undefined'] = function (ASSERT) { | ||
var r = Q.resolve(); | ||
ASSERT.ok(Q.isResolved(r), 'isResolved'); | ||
@@ -28,5 +28,5 @@ ASSERT.equal(r.valueOf(), undefined, 'valueOf'); | ||
exports['test ref defined'] = function (ASSERT) { | ||
exports['test resolve defined'] = function (ASSERT) { | ||
var o = {}; | ||
var r = Q.ref(o); | ||
var r = Q.resolve(o); | ||
ASSERT.ok(Q.isResolved(r), 'isResolved'); | ||
@@ -33,0 +33,0 @@ ASSERT.ok(r.valueOf() === o, 'valueOf'); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
352254
8410
635
57
2