Update Q library
This commit is contained in:
parent
0e3d68bdd9
commit
0b89ccadf9
320
resource/q.js
320
resource/q.js
|
@ -2,8 +2,8 @@
|
|||
/*jshint browser: true, node: true,
|
||||
curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true,
|
||||
undef: true */
|
||||
/*global define: false, Q: true, msSetImmediate: false, setImmediate: false,
|
||||
ReturnValue: false, cajaVM: false, ses: false */
|
||||
/*global define: false, Q: true, setImmediate: false,
|
||||
ReturnValue: false, cajaVM: false, ses: false, bootstrap: false */
|
||||
/*!
|
||||
*
|
||||
* Copyright 2009-2012 Kris Kowal under the terms of the MIT
|
||||
|
@ -67,14 +67,18 @@
|
|||
// Common/Node/RequireJS, the module exports the Q API and when
|
||||
// executed as a simple <script>, it creates a Q global instead.
|
||||
|
||||
// RequireJS
|
||||
if (typeof define === "function") {
|
||||
define(definition);
|
||||
// Montage Require
|
||||
if (typeof bootstrap === "function") {
|
||||
bootstrap("promise", definition);
|
||||
|
||||
// CommonJS
|
||||
} else if (typeof exports === "object") {
|
||||
definition(void 0, exports);
|
||||
|
||||
// RequireJS
|
||||
} else if (typeof define === "function") {
|
||||
define(definition);
|
||||
|
||||
// SES (Secure EcmaScript)
|
||||
} else if (typeof ses !== "undefined") {
|
||||
if (!ses.ok()) {
|
||||
|
@ -133,7 +137,7 @@
|
|||
}
|
||||
};
|
||||
definition(void 0, Q = {});
|
||||
|
||||
|
||||
// <script>
|
||||
} else {
|
||||
definition(void 0, Q = {});
|
||||
|
@ -142,6 +146,11 @@
|
|||
})(function (require, exports) {
|
||||
"use strict";
|
||||
|
||||
// All code after this point will be filtered from stack traces reported
|
||||
// by Q.
|
||||
var qStartingLine = captureLine();
|
||||
var qFileName;
|
||||
|
||||
// shims
|
||||
|
||||
// used for fallback "defend" and in "allResolved"
|
||||
|
@ -163,12 +172,8 @@ var nextTick;
|
|||
if (typeof process !== "undefined") {
|
||||
// node
|
||||
nextTick = process.nextTick;
|
||||
} else if (typeof msSetImmediate === "function") {
|
||||
// IE 10 only, at the moment
|
||||
// And yes, ``bind``ing to ``window`` is necessary O_o.
|
||||
nextTick = msSetImmediate.bind(window);
|
||||
} else if (typeof setImmediate === "function") {
|
||||
// https://github.com/NobleJS/setImmediate
|
||||
// In IE10, or use https://github.com/NobleJS/setImmediate
|
||||
nextTick = setImmediate;
|
||||
} else if (typeof MessageChannel !== "undefined") {
|
||||
// modern browsers
|
||||
|
@ -212,7 +217,7 @@ if (Function.prototype.bind) {
|
|||
uncurryThis = Function_bind.bind(Function_bind.call);
|
||||
} else {
|
||||
uncurryThis = function (f) {
|
||||
return function (thisp) {
|
||||
return function () {
|
||||
return f.call.apply(f, arguments);
|
||||
};
|
||||
};
|
||||
|
@ -397,6 +402,14 @@ function formatSourcePosition(frame) {
|
|||
return line;
|
||||
}
|
||||
|
||||
function isInternalFrame(fileName, frame) {
|
||||
if (fileName !== qFileName) {
|
||||
return false;
|
||||
}
|
||||
var line = frame.getLineNumber();
|
||||
return line >= qStartingLine && line <= qEndingLine;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves an array of structured stack frames parsed from the ``stack``
|
||||
* property of a given object.
|
||||
|
@ -417,7 +430,7 @@ function getStackFrames(objectWithStack) {
|
|||
return (
|
||||
fileName !== "module.js" &&
|
||||
fileName !== "node.js" &&
|
||||
fileName !== qFileName
|
||||
!isInternalFrame(fileName, frame)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
@ -429,16 +442,17 @@ function getStackFrames(objectWithStack) {
|
|||
return stack;
|
||||
}
|
||||
|
||||
// discover own file name for filtering stack traces
|
||||
var qFileName;
|
||||
if (Error.captureStackTrace) {
|
||||
qFileName = (function () {
|
||||
var fileName;
|
||||
// discover own file name and line number range for filtering stack
|
||||
// traces
|
||||
function captureLine() {
|
||||
if (Error.captureStackTrace) {
|
||||
var fileName, lineNumber;
|
||||
|
||||
var oldPrepareStackTrace = Error.prepareStackTrace;
|
||||
|
||||
Error.prepareStackTrace = function (error, frames) {
|
||||
fileName = frames[0].getFileName();
|
||||
fileName = frames[1].getFileName();
|
||||
lineNumber = frames[1].getLineNumber();
|
||||
};
|
||||
|
||||
// teases call of temporary prepareStackTrace
|
||||
|
@ -447,17 +461,17 @@ if (Error.captureStackTrace) {
|
|||
new Error().stack;
|
||||
|
||||
Error.prepareStackTrace = oldPrepareStackTrace;
|
||||
|
||||
return fileName;
|
||||
})();
|
||||
qFileName = fileName;
|
||||
return lineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
function deprecate(fn, name, alternative){
|
||||
function deprecate(callback, name, alternative) {
|
||||
return function () {
|
||||
if (typeof console !== "undefined" && typeof console.warn === "function"){
|
||||
console.warn(name + " is deprecated, use " + alternative + " instead.");
|
||||
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
||||
console.warn(name + " is deprecated, use " + alternative + " instead.", new Error("").stack);
|
||||
}
|
||||
return fn.apply(fn,arguments);
|
||||
return callback.apply(callback, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -487,15 +501,18 @@ function defer() {
|
|||
// forward to the resolved promise. We coerce the resolution value to a
|
||||
// promise using the ref promise because it handles both fully
|
||||
// resolved values and other promises gracefully.
|
||||
var pending = [], value;
|
||||
var pending = [], progressListeners = [], value;
|
||||
|
||||
var deferred = object_create(defer.prototype);
|
||||
var promise = object_create(makePromise.prototype);
|
||||
|
||||
promise.promiseSend = function () {
|
||||
promise.promiseSend = function (op, _, __, progress) {
|
||||
var args = array_slice(arguments);
|
||||
if (pending) {
|
||||
pending.push(args);
|
||||
if (op === "when" && progress) {
|
||||
progressListeners.push(progress);
|
||||
}
|
||||
} else {
|
||||
nextTick(function () {
|
||||
value.promiseSend.apply(value, args);
|
||||
|
@ -525,6 +542,7 @@ function defer() {
|
|||
});
|
||||
}, void 0);
|
||||
pending = void 0;
|
||||
progressListeners = void 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -535,6 +553,17 @@ function defer() {
|
|||
deferred.reject = function (exception) {
|
||||
return become(reject(exception));
|
||||
};
|
||||
deferred.notify = function () {
|
||||
if (pending) {
|
||||
var args = arguments;
|
||||
|
||||
array_reduce(progressListeners, function (undefined, progressListener) {
|
||||
nextTick(function () {
|
||||
progressListener.apply(void 0, args);
|
||||
});
|
||||
}, void 0);
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
}
|
||||
|
@ -561,18 +590,18 @@ defer.prototype.node = deprecate(defer.prototype.makeNodeResolver, "node", "make
|
|||
|
||||
/**
|
||||
* @param makePromise {Function} a function that returns nothing and accepts
|
||||
* the resolve and reject functions for a deferred.
|
||||
* the resolve, reject, and notify 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;
|
||||
function promise(makePromise) {
|
||||
var deferred = defer();
|
||||
call(
|
||||
fcall(
|
||||
makePromise,
|
||||
void 0,
|
||||
deferred.resolve,
|
||||
deferred.reject
|
||||
deferred.reject,
|
||||
deferred.notify
|
||||
).fail(deferred.reject);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
@ -610,7 +639,9 @@ function makePromise(descriptor, fallback, valueOf, exception) {
|
|||
} catch (exception) {
|
||||
result = reject(exception);
|
||||
}
|
||||
resolved(result);
|
||||
if (resolved) {
|
||||
resolved(result);
|
||||
}
|
||||
};
|
||||
|
||||
if (valueOf) {
|
||||
|
@ -627,8 +658,12 @@ function makePromise(descriptor, fallback, valueOf, exception) {
|
|||
}
|
||||
|
||||
// provide thenables, CommonJS/Promises/A
|
||||
makePromise.prototype.then = function (fulfilled, rejected) {
|
||||
return when(this, fulfilled, rejected);
|
||||
makePromise.prototype.then = function (fulfilled, rejected, progressed) {
|
||||
return when(this, fulfilled, rejected, progressed);
|
||||
};
|
||||
|
||||
makePromise.prototype.thenResolve = function (value) {
|
||||
return when(this, function () { return value; });
|
||||
};
|
||||
|
||||
// Chainable methods
|
||||
|
@ -644,9 +679,12 @@ array_reduce(
|
|||
"all", "allResolved",
|
||||
"view", "viewInfo",
|
||||
"timeout", "delay",
|
||||
"catch", "finally", "fail", "fin", "end"
|
||||
"catch", "finally", "fail", "fin", "progress", "end", "done",
|
||||
"ncall", "napply", "nbind",
|
||||
"npost", "ninvoke",
|
||||
"nend"
|
||||
],
|
||||
function (prev, name) {
|
||||
function (undefined, name) {
|
||||
makePromise.prototype[name] = function () {
|
||||
return exports[name].apply(
|
||||
exports,
|
||||
|
@ -726,12 +764,21 @@ function isRejected(object) {
|
|||
|
||||
var rejections = [];
|
||||
var errors = [];
|
||||
if (typeof window !== "undefined" && window.console) {
|
||||
// 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);
|
||||
var errorsDisplayed;
|
||||
function displayErrors() {
|
||||
if (
|
||||
!errorsDisplayed &&
|
||||
typeof window !== "undefined" &&
|
||||
!window.Touch &&
|
||||
window.console
|
||||
) {
|
||||
// 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);
|
||||
}
|
||||
errorsDisplayed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -753,12 +800,13 @@ function reject(exception) {
|
|||
}
|
||||
return rejected ? rejected(exception) : reject(exception);
|
||||
}
|
||||
}, function fallback(op) {
|
||||
}, function fallback() {
|
||||
return reject(exception);
|
||||
}, function valueOf() {
|
||||
return this;
|
||||
}, exception);
|
||||
// note that the error has not been handled
|
||||
displayErrors();
|
||||
rejections.push(rejection);
|
||||
errors.push(exception);
|
||||
return rejection;
|
||||
|
@ -778,24 +826,35 @@ function resolve(object) {
|
|||
if (isPromise(object)) {
|
||||
return object;
|
||||
}
|
||||
// In order to break infinite recursion or loops between `then` and
|
||||
// `resolve`, it is necessary to attempt to extract fulfilled values
|
||||
// out of foreign promise implementations before attempting to wrap
|
||||
// them as unresolved promises. It is my hope that other
|
||||
// implementations will implement `valueOf` to synchronously extract
|
||||
// the fulfillment value from their fulfilled promises. If the
|
||||
// other promise library does not implement `valueOf`, the
|
||||
// implementations on primordial prototypes are harmless.
|
||||
object = valueOf(object);
|
||||
// assimilate thenables, CommonJS/Promises/A
|
||||
if (object && typeof object.then === "function") {
|
||||
var result = defer();
|
||||
object.then(result.resolve, result.reject);
|
||||
return result.promise;
|
||||
var deferred = defer();
|
||||
object.then(deferred.resolve, deferred.reject, deferred.notify);
|
||||
return deferred.promise;
|
||||
}
|
||||
return makePromise({
|
||||
"when": function (rejected) {
|
||||
"when": function () {
|
||||
return object;
|
||||
},
|
||||
"get": function (name) {
|
||||
return object[name];
|
||||
},
|
||||
"put": function (name, value) {
|
||||
return object[name] = value;
|
||||
object[name] = value;
|
||||
return object;
|
||||
},
|
||||
"del": function (name) {
|
||||
return delete object[name];
|
||||
delete object[name];
|
||||
return object;
|
||||
},
|
||||
"post": function (name, value) {
|
||||
return object[name].apply(object, value);
|
||||
|
@ -846,7 +905,7 @@ exports.master = master;
|
|||
function master(object) {
|
||||
return makePromise({
|
||||
"isDef": function () {}
|
||||
}, function fallback(op) {
|
||||
}, function fallback() {
|
||||
var args = array_slice(arguments);
|
||||
return send.apply(void 0, [object].concat(args));
|
||||
}, function () {
|
||||
|
@ -862,7 +921,7 @@ function viewInfo(object, info) {
|
|||
"viewInfo": function () {
|
||||
return info;
|
||||
}
|
||||
}, function fallback(op) {
|
||||
}, function fallback() {
|
||||
var args = array_slice(arguments);
|
||||
return send.apply(void 0, [object].concat(args));
|
||||
}, function () {
|
||||
|
@ -906,13 +965,14 @@ function view(object) {
|
|||
* called, but not both.
|
||||
* 3. that fulfilled and rejected will not be called in this turn.
|
||||
*
|
||||
* @param value promise or immediate reference to observe
|
||||
* @param fulfilled function to be called with the fulfilled value
|
||||
* @param rejected function to be called with the rejection exception
|
||||
* @param value promise or immediate reference to observe
|
||||
* @param fulfilled function to be called with the fulfilled value
|
||||
* @param rejected function to be called with the rejection exception
|
||||
* @param progressed function to be called on any progress notifications
|
||||
* @return promise for the return value from the invoked callback
|
||||
*/
|
||||
exports.when = when;
|
||||
function when(value, fulfilled, rejected) {
|
||||
function when(value, fulfilled, rejected, progressed) {
|
||||
var deferred = defer();
|
||||
var done = false; // ensure the untrusted promise makes at most a
|
||||
// single call to one of the callbacks
|
||||
|
@ -933,26 +993,30 @@ function when(value, fulfilled, rejected) {
|
|||
}
|
||||
}
|
||||
|
||||
var resolvedValue = resolve(value);
|
||||
nextTick(function () {
|
||||
resolve(value).promiseSend("when", function (value) {
|
||||
resolvedValue.promiseSend("when", function (value) {
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
resolve(value).promiseSend("when", function (value) {
|
||||
deferred.resolve(_fulfilled(value));
|
||||
}, function (exception) {
|
||||
deferred.resolve(_rejected(exception));
|
||||
});
|
||||
|
||||
deferred.resolve(_fulfilled(value));
|
||||
}, function (exception) {
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
|
||||
deferred.resolve(_rejected(exception));
|
||||
});
|
||||
});
|
||||
|
||||
// Progress listeners need to be attached in the current tick.
|
||||
if (progressed) {
|
||||
resolvedValue.promiseSend("when", void 0, void 0, progressed);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -968,8 +1032,10 @@ function when(value, fulfilled, rejected) {
|
|||
*/
|
||||
exports.spread = spread;
|
||||
function spread(promise, fulfilled, rejected) {
|
||||
return when(promise, function (values) {
|
||||
return fulfilled.apply(void 0, values);
|
||||
return when(promise, function (valuesOrPromises) {
|
||||
return all(valuesOrPromises).then(function (values) {
|
||||
return fulfilled.apply(void 0, values);
|
||||
});
|
||||
}, rejected);
|
||||
}
|
||||
|
||||
|
@ -1049,6 +1115,30 @@ function _return(value) {
|
|||
throw new QReturnValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The promised function decorator ensures that any promise arguments
|
||||
* are resolved and passed as values (`this` is also resolved and passed
|
||||
* as a value). It will also ensure that the result of a function is
|
||||
* always a promise.
|
||||
*
|
||||
* @example
|
||||
* var add = Q.promised(function (a, b) {
|
||||
* return a + b;
|
||||
* });
|
||||
* add(Q.resolve(a), Q.resolve(B));
|
||||
*
|
||||
* @param {function} callback The function to decorate
|
||||
* @returns {function} a function that has been decorated.
|
||||
*/
|
||||
exports.promised = promised;
|
||||
function promised(callback) {
|
||||
return function () {
|
||||
return all([this, all(arguments)]).spread(function (self, args) {
|
||||
return callback.apply(self, args);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -1268,13 +1358,20 @@ function all(promises) {
|
|||
}
|
||||
var deferred = defer();
|
||||
array_reduce(promises, function (undefined, promise, index) {
|
||||
when(promise, function (value) {
|
||||
promises[index] = value;
|
||||
if (isFulfilled(promise)) {
|
||||
promises[index] = valueOf(promise);
|
||||
if (--countDown === 0) {
|
||||
deferred.resolve(promises);
|
||||
}
|
||||
})
|
||||
.fail(deferred.reject);
|
||||
} else {
|
||||
when(promise, function (value) {
|
||||
promises[index] = value;
|
||||
if (--countDown === 0) {
|
||||
deferred.resolve(promises);
|
||||
}
|
||||
})
|
||||
.fail(deferred.reject);
|
||||
}
|
||||
}, void 0);
|
||||
return deferred.promise;
|
||||
});
|
||||
|
@ -1315,6 +1412,20 @@ function fail(promise, rejected) {
|
|||
return when(promise, void 0, rejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a listener that can respond to progress notifications from a
|
||||
* promise's originating deferred. This listener receives the exact arguments
|
||||
* passed to ``deferred.notify``.
|
||||
* @param {Any*} promise for something
|
||||
* @param {Function} callback to receive any progress notifications
|
||||
* @returns the given promise, unchanged
|
||||
*/
|
||||
exports.progress = progress;
|
||||
function progress(promise, progressed) {
|
||||
when(promise, void 0, void 0, progressed);
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an opportunity to observe the rejection of a promise,
|
||||
* regardless of whether the promise is fulfilled or rejected. Forwards
|
||||
|
@ -1346,30 +1457,49 @@ function fin(promise, callback) {
|
|||
* @param {Any*} promise at the end of a chain of promises
|
||||
* @returns nothing
|
||||
*/
|
||||
exports.end = end; // XXX stopgap
|
||||
function end(promise) {
|
||||
when(promise, void 0, function (error) {
|
||||
exports.end = deprecate(done, "end", "done"); // XXX deprecated, use done
|
||||
exports.done = done;
|
||||
function done(promise, fulfilled, rejected, progress) {
|
||||
function onUnhandledError(error) {
|
||||
// forward to a future turn so that ``when``
|
||||
// does not catch it and turn it into a rejection.
|
||||
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 && typeof error === "object" &&
|
||||
"stack" in error) {
|
||||
var errorStackFrames = getStackFrames(error);
|
||||
// the stack trace of the promise we are ``done``ing. See #57.
|
||||
var errorStackFrames;
|
||||
if (
|
||||
Error.captureStackTrace &&
|
||||
typeof error === "object" &&
|
||||
(errorStackFrames = getStackFrames(error))
|
||||
) {
|
||||
var promiseStackFrames = getStackFrames(promise);
|
||||
|
||||
var combinedStackFrames = errorStackFrames.concat(
|
||||
"From previous event:",
|
||||
promiseStackFrames
|
||||
);
|
||||
error.stack = formatStackTrace(error, combinedStackFrames);
|
||||
// Check to make sure the stack trace hasn't already been
|
||||
// rendered (possibly by us).
|
||||
if (typeof errorStackFrames !== "string") {
|
||||
var combinedStackFrames = errorStackFrames.concat(
|
||||
"From previous event:",
|
||||
promiseStackFrames
|
||||
);
|
||||
error.stack = formatStackTrace(error, combinedStackFrames);
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
if (exports.onerror) {
|
||||
exports.onerror(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Avoid unnecessary `nextTick`ing via an unnecessary `when`.
|
||||
var promiseToHandle = fulfilled || rejected || progress ?
|
||||
when(promise, fulfilled, rejected, progress) :
|
||||
promise;
|
||||
|
||||
fail(promiseToHandle, onUnhandledError);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1419,7 +1549,7 @@ function delay(promise, timeout) {
|
|||
* 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");
|
||||
* var FS = (require)("fs");
|
||||
* Q.napply(FS.readFile, FS, [__filename])
|
||||
* .then(function (content) {
|
||||
* })
|
||||
|
@ -1434,7 +1564,7 @@ function napply(callback, 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");
|
||||
* var FS = (require)("fs");
|
||||
* Q.ncall(FS.readFile, FS, __filename)
|
||||
* .then(function (content) {
|
||||
* })
|
||||
|
@ -1452,7 +1582,7 @@ function ncall(callback, thisp /*, ...args*/) {
|
|||
*
|
||||
* Q.nbind(FS.readFile, FS)(__filename)
|
||||
* .then(console.log)
|
||||
* .end()
|
||||
* .done()
|
||||
*
|
||||
*/
|
||||
exports.nbind = nbind;
|
||||
|
@ -1509,6 +1639,24 @@ function ninvoke(object, name /*, ...args*/) {
|
|||
return napply(object[name], object, args);
|
||||
}
|
||||
|
||||
defend(exports);
|
||||
exports.nend = nend;
|
||||
function nend(promise, nodeback) {
|
||||
if (nodeback) {
|
||||
promise.then(function (value) {
|
||||
nextTick(function () {
|
||||
nodeback(null, value);
|
||||
});
|
||||
}, function (error) {
|
||||
nextTick(function () {
|
||||
nodeback(error);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
// All code before this point will be filtered from stack traces.
|
||||
var qEndingLine = captureLine();
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user