Comparing version 0.9.3 to 0.9.4
{ | ||
"name": "q", | ||
"version": "0.9.3", | ||
"version": "0.9.4", | ||
"description": "A library for promises (CommonJS/Promises/A,B,D)", | ||
@@ -12,3 +12,3 @@ "homepage": "https://github.com/kriskowal/q", | ||
"promises-a", | ||
"promises-a-plus", | ||
"promises-aplus", | ||
"deferred", | ||
@@ -15,0 +15,0 @@ "future", |
308
q.js
@@ -66,2 +66,9 @@ // vim:ts=4:sts=4:sw=4: | ||
var hasStacks = false; | ||
try { | ||
throw new Error(); | ||
} catch (e) { | ||
hasStacks = !!e.stack; | ||
} | ||
// All code after this point will be filtered from stack traces reported | ||
@@ -257,4 +264,9 @@ // by Q. | ||
function isObject(value) { | ||
return value === Object(value); | ||
} | ||
// generator related shims | ||
// FIXME: Remove this function once ES6 generators are in SpiderMonkey. | ||
function isStopIteration(exception) { | ||
@@ -267,2 +279,4 @@ return ( | ||
// FIXME: Remove this helper and Q.return once ES6 generators are in | ||
// SpiderMonkey. | ||
var QReturnValue; | ||
@@ -277,2 +291,17 @@ if (typeof ReturnValue !== "undefined") { | ||
// Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only | ||
// engine that has a deployed base of browsers that support generators. | ||
// However, SM's generators use the Python-inspired semantics of | ||
// outdated ES6 drafts. We would like to support ES6, but we'd also | ||
// like to make it possible to use generators in deployed browsers, so | ||
// we also support Python-style generators. At some point we can remove | ||
// this block. | ||
var hasES6Generators; | ||
try { | ||
new Function("(function* (){ yield 1; })"); | ||
hasES6Generators = true; | ||
} catch (e) { | ||
hasES6Generators = false; | ||
} | ||
// long stack traces | ||
@@ -285,6 +314,6 @@ | ||
function makeStackTraceLong(error, promise) { | ||
// 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 ``done``ing. See #57. | ||
if (promise.stack && | ||
// If possible, transform the error stack trace by removing Node and Q | ||
// cruft, then concatenating with the stack trace of `promise`. See #57. | ||
if (hasStacks && | ||
promise.stack && | ||
typeof error === "object" && | ||
@@ -307,3 +336,3 @@ error !== null && | ||
if (!isInternalFrame(line) && !isNodeFrame(line)) { | ||
if (!isInternalFrame(line) && !isNodeFrame(line) && line) { | ||
desiredLines.push(line); | ||
@@ -320,11 +349,32 @@ } | ||
function getFileNameAndLineNumber(stackLine) { | ||
// Named functions: "at functionName (filename:lineNumber:columnNumber)" | ||
// In IE10 function name can have spaces ("Anonymous function") O_o | ||
var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine); | ||
if (attempt1) { | ||
return [attempt1[1], Number(attempt1[2])]; | ||
} | ||
// Anonymous functions: "at filename:lineNumber:columnNumber" | ||
var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine); | ||
if (attempt2) { | ||
return [attempt2[1], Number(attempt2[2])]; | ||
} | ||
// Firefox style: "function@filename:lineNumber or @filename:lineNumber" | ||
var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine); | ||
if (attempt3) { | ||
return [attempt3[1], Number(attempt3[2])]; | ||
} | ||
} | ||
function isInternalFrame(stackLine) { | ||
var pieces = /at .+ \((.*):(\d+):\d+\)/.exec(stackLine); | ||
var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine); | ||
if (!pieces) { | ||
if (!fileNameAndLineNumber) { | ||
return false; | ||
} | ||
var fileName = pieces[1]; | ||
var lineNumber = pieces[2]; | ||
var fileName = fileNameAndLineNumber[0]; | ||
var lineNumber = fileNameAndLineNumber[1]; | ||
@@ -339,20 +389,18 @@ return fileName === qFileName && | ||
function captureLine() { | ||
if (Error.captureStackTrace) { | ||
var fileName, lineNumber; | ||
if (!hasStacks) { | ||
return; | ||
} | ||
var oldPrepareStackTrace = Error.prepareStackTrace; | ||
try { | ||
throw new Error(); | ||
} catch (e) { | ||
var lines = e.stack.split("\n"); | ||
var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2]; | ||
var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine); | ||
if (!fileNameAndLineNumber) { | ||
return; | ||
} | ||
Error.prepareStackTrace = function (error, frames) { | ||
fileName = frames[1].getFileName(); | ||
lineNumber = frames[1].getLineNumber(); | ||
}; | ||
// teases call of temporary prepareStackTrace | ||
// JSHint and Closure Compiler generate known warnings here | ||
/*jshint expr: true */ | ||
new Error().stack; | ||
Error.prepareStackTrace = oldPrepareStackTrace; | ||
qFileName = fileName; | ||
return lineNumber; | ||
qFileName = fileNameAndLineNumber[0]; | ||
return fileNameAndLineNumber[1]; | ||
} | ||
@@ -390,9 +438,9 @@ } | ||
function defer() { | ||
// if "pending" is an "Array", that indicates that the promise has not yet | ||
// if "messages" is an "Array", that indicates that the promise has not yet | ||
// been resolved. If it is "undefined", it has been resolved. Each | ||
// element of the pending array is itself an array of complete arguments to | ||
// element of the messages array is itself an array of complete arguments to | ||
// forward to the resolved promise. We coerce the resolution value to a | ||
// promise using the ref promise because it handles both fully | ||
// promise using the `resolve` function because it handles both fully | ||
// resolved values and other promises gracefully. | ||
var pending = [], progressListeners = [], resolvedPromise; | ||
var messages = [], progressListeners = [], resolvedPromise; | ||
@@ -404,4 +452,4 @@ var deferred = object_create(defer.prototype); | ||
var args = array_slice(arguments); | ||
if (pending) { | ||
pending.push(args); | ||
if (messages) { | ||
messages.push(args); | ||
if (op === "when" && operands[1]) { // progress operand | ||
@@ -418,3 +466,3 @@ progressListeners.push(operands[1]); | ||
promise.valueOf = function () { | ||
if (pending) { | ||
if (messages) { | ||
return promise; | ||
@@ -429,11 +477,14 @@ } | ||
if (Error.captureStackTrace && Q.longStackJumpLimit > 0) { | ||
Error.captureStackTrace(promise, defer); | ||
// Reify the stack into a string by using the accessor; this prevents | ||
// memory leaks as per GH-111. At the same time, cut off the first line; | ||
// it's always just "[object Promise]\n", as per the `toString`. | ||
promise.stack = promise.stack.substring( | ||
promise.stack.indexOf("\n") + 1 | ||
); | ||
if (Q.longStackJumpLimit > 0 && hasStacks) { | ||
try { | ||
throw new Error(); | ||
} catch (e) { | ||
// NOTE: don't try to use `Error.captureStackTrace` or transfer the | ||
// accessor around; that causes memory leaks as per GH-111. Just | ||
// reify the stack trace as a string ASAP. | ||
// | ||
// At the same time, cut off the first line; it's always just | ||
// "[object Promise]\n", as per the `toString`. | ||
promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1); | ||
} | ||
} | ||
@@ -448,9 +499,9 @@ | ||
array_reduce(pending, function (undefined, pending) { | ||
array_reduce(messages, function (undefined, message) { | ||
nextTick(function () { | ||
promise.promiseDispatch.apply(promise, pending); | ||
promise.promiseDispatch.apply(promise, message); | ||
}); | ||
}, void 0); | ||
pending = void 0; | ||
messages = void 0; | ||
progressListeners = void 0; | ||
@@ -659,3 +710,3 @@ } | ||
function isPromise(object) { | ||
return object && typeof object.promiseDispatch === "function"; | ||
return isObject(object) && typeof object.promiseDispatch === "function"; | ||
} | ||
@@ -665,3 +716,3 @@ | ||
function isPromiseAlike(object) { | ||
return object && typeof object.then === "function"; | ||
return isObject(object) && typeof object.then === "function"; | ||
} | ||
@@ -696,2 +747,4 @@ | ||
//// BEGIN UNHANDLED REJECTION TRACKING | ||
// This promise library consumes exceptions thrown in handlers so they can be | ||
@@ -701,5 +754,6 @@ // handled by a subsequent promise. The exceptions get added to this array when | ||
// shimmed environments, this would naturally be a `Set`. | ||
var unhandledReasons = Q.unhandledReasons = []; | ||
var unhandledReasons = []; | ||
var unhandledRejections = []; | ||
var unhandledReasonsDisplayed = false; | ||
var trackUnhandledRejections = true; | ||
function displayUnhandledReasons() { | ||
@@ -719,18 +773,71 @@ if ( | ||
// Show unhandled rejection reasons if Node exits without handling an | ||
// outstanding rejection. (Note that Browserify presently produces a process | ||
// global without the `EventEmitter` `on` method.) | ||
if (typeof process !== "undefined" && process.on) { | ||
process.on("exit", function () { | ||
for (var i = 0; i < unhandledReasons.length; i++) { | ||
var reason = unhandledReasons[i]; | ||
if (reason && typeof reason.stack !== "undefined") { | ||
console.warn("Unhandled rejection reason:", reason.stack); | ||
} else { | ||
console.warn("Unhandled rejection reason (no stack):", reason); | ||
} | ||
function logUnhandledReasons() { | ||
for (var i = 0; i < unhandledReasons.length; i++) { | ||
var reason = unhandledReasons[i]; | ||
if (reason && typeof reason.stack !== "undefined") { | ||
console.warn("Unhandled rejection reason:", reason.stack); | ||
} else { | ||
console.warn("Unhandled rejection reason (no stack):", reason); | ||
} | ||
}); | ||
} | ||
} | ||
function resetUnhandledRejections() { | ||
unhandledReasons.length = 0; | ||
unhandledRejections.length = 0; | ||
unhandledReasonsDisplayed = false; | ||
if (!trackUnhandledRejections) { | ||
trackUnhandledRejections = true; | ||
// Show unhandled rejection reasons if Node exits without handling an | ||
// outstanding rejection. (Note that Browserify presently produces a | ||
// `process` global without the `EventEmitter` `on` method.) | ||
if (typeof process !== "undefined" && process.on) { | ||
process.on("exit", logUnhandledReasons); | ||
} | ||
} | ||
} | ||
function trackRejection(promise, reason) { | ||
if (!trackUnhandledRejections) { | ||
return; | ||
} | ||
unhandledRejections.push(promise); | ||
unhandledReasons.push(reason); | ||
displayUnhandledReasons(); | ||
} | ||
function untrackRejection(promise, reason) { | ||
if (!trackUnhandledRejections) { | ||
return; | ||
} | ||
var at = array_indexOf(unhandledRejections, promise); | ||
if (at !== -1) { | ||
unhandledRejections.splice(at, 1); | ||
unhandledReasons.splice(at, 1); | ||
} | ||
} | ||
Q.resetUnhandledRejections = resetUnhandledRejections; | ||
Q.getUnhandledReasons = function () { | ||
// Make a copy so that consumers can't interfere with our internal state. | ||
return unhandledReasons.slice(); | ||
}; | ||
Q.stopUnhandledRejectionTracking = function () { | ||
resetUnhandledRejections(); | ||
if (typeof process !== "undefined" && process.on) { | ||
process.removeListener("exit", logUnhandledReasons); | ||
} | ||
trackUnhandledRejections = false; | ||
}; | ||
resetUnhandledRejections(); | ||
//// END UNHANDLED REJECTION TRACKING | ||
/** | ||
@@ -746,7 +853,3 @@ * Constructs a rejected promise. | ||
if (rejected) { | ||
var at = array_indexOf(unhandledRejections, this); | ||
if (at !== -1) { | ||
unhandledRejections.splice(at, 1); | ||
unhandledReasons.splice(at, 1); | ||
} | ||
untrackRejection(this); | ||
} | ||
@@ -756,3 +859,3 @@ return rejected ? rejected(reason) : this; | ||
}, function fallback() { | ||
return reject(reason); | ||
return this; | ||
}, function valueOf() { | ||
@@ -763,5 +866,3 @@ return this; | ||
// Note that the reason has not been handled. | ||
displayUnhandledReasons(); | ||
unhandledRejections.push(rejection); | ||
unhandledReasons.push(reason); | ||
trackRejection(rejection, reason); | ||
@@ -986,7 +1087,12 @@ return rejection; | ||
* The async function is a decorator for generator functions, turning | ||
* them into asynchronous generators. This presently only works in | ||
* Firefox/Spidermonkey, however, this code does not cause syntax | ||
* errors in older engines. This code should continue to work and | ||
* will in fact improve over time as the language improves. | ||
* them into asynchronous generators. Although generators are only part | ||
* of the newest ECMAScript 6 drafts, this code does not cause syntax | ||
* errors in older engines. This code should continue to work and will | ||
* in fact improve over time as the language improves. | ||
* | ||
* ES6 generators are currently part of V8 version 3.19 with the | ||
* --harmony-generators runtime flag enabled. SpiderMonkey has had them | ||
* for longer, but under an older Python-inspired form. This function | ||
* works on both kinds of generators. | ||
* | ||
* Decorates a generator function such that: | ||
@@ -1005,14 +1111,2 @@ * - it may yield promises | ||
* rejection for the promise returned by the decorated generator. | ||
* - in present implementations of generators, when a generator | ||
* function is complete, it throws ``StopIteration``, ``return`` is | ||
* a syntax error in the presence of ``yield``, so there is no | ||
* observable return value. There is a proposal[1] to add support | ||
* for ``return``, which would permit the value to be carried by a | ||
* ``StopIteration`` instance, in which case it would fulfill the | ||
* promise returned by the asynchronous generator. This can be | ||
* emulated today by throwing StopIteration explicitly with a value | ||
* property. | ||
* | ||
* [1]: http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation | ||
* | ||
*/ | ||
@@ -1026,12 +1120,26 @@ Q.async = async; | ||
var result; | ||
try { | ||
result = generator[verb](arg); | ||
} catch (exception) { | ||
if (isStopIteration(exception)) { | ||
return exception.value; | ||
} else { | ||
if (hasES6Generators) { | ||
try { | ||
result = generator[verb](arg); | ||
} catch (exception) { | ||
return reject(exception); | ||
} | ||
if (result.done) { | ||
return result.value; | ||
} else { | ||
return when(result.value, callback, errback); | ||
} | ||
} else { | ||
// FIXME: Remove this case when SM does ES6 generators. | ||
try { | ||
result = generator[verb](arg); | ||
} catch (exception) { | ||
if (isStopIteration(exception)) { | ||
return exception.value; | ||
} else { | ||
return reject(exception); | ||
} | ||
} | ||
return when(result, callback, errback); | ||
} | ||
return when(result, callback, errback); | ||
} | ||
@@ -1045,9 +1153,21 @@ var generator = makeGenerator.apply(this, arguments); | ||
// FIXME: Remove this interface once ES6 generators are in SpiderMonkey. | ||
/** | ||
* Throws a ReturnValue exception to stop an asynchronous generator. | ||
* Only useful presently in Firefox/SpiderMonkey since generators are | ||
* implemented. | ||
* | ||
* This interface is a stop-gap measure to support generator return | ||
* values in older Firefox/SpiderMonkey. In browsers that support ES6 | ||
* generators like Chromium 29, just use "return" in your generator | ||
* functions. | ||
* | ||
* @param value the return value for the surrounding generator | ||
* @throws ReturnValue exception with the value. | ||
* @example | ||
* // ES6 style | ||
* Q.async(function* () { | ||
* var foo = yield getFooPromise(); | ||
* var bar = yield getBarPromise(); | ||
* return foo + bar; | ||
* }) | ||
* // Older SpiderMonkey style | ||
* Q.async(function () { | ||
@@ -1054,0 +1174,0 @@ * var foo = yield getFooPromise(); |
@@ -75,3 +75,3 @@ [![Build Status](https://secure.travis-ci.org/kriskowal/q.png?branch=master)](http://travis-ci.org/kriskowal/q) | ||
- A [component](https://github.com/component/component) as ``microjs/q`` | ||
- Using [bower](http://twitter.github.com/bower/) as ``microjs/q`` | ||
- Using [bower](http://bower.io/) as ``q`` | ||
- Using [NuGet](http://nuget.org/) as [Q](https://nuget.org/packages/q) | ||
@@ -551,3 +551,3 @@ | ||
} else { | ||
onerror(); | ||
deferred.reject(new Error("Status code was " + request.status)); | ||
} | ||
@@ -557,3 +557,3 @@ } | ||
function onerror() { | ||
deferred.reject("Can't XHR " + JSON.stringify(url)); | ||
deferred.reject(new Error("Can't XHR " + JSON.stringify(url))); | ||
} | ||
@@ -569,3 +569,18 @@ | ||
Below is an example of how to use this ``requestOkText`` function: | ||
```javascript | ||
requestOkText("http://localhost:3000") | ||
.then(function (responseText) { | ||
// If the HTTP response returns 200 OK, log the response text. | ||
console.log(responseText); | ||
}, function (error) { | ||
// If there's an error or a non-200 status code, log the error. | ||
console.error(error); | ||
}, function (progress) { | ||
// Log the progress as it comes in. | ||
console.log("Request progress: " + Math.round(progress * 100) + "%"); | ||
}); | ||
``` | ||
### The Middle | ||
@@ -572,0 +587,0 @@ |
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
587051
14
1576
805