1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525 |
- // vim:ts=4:sts=4:sw=4:
- /*!
- *
- * 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
- * at http://www.opensource.org/licenses/mit-license.html
- * Forked at ref_send.js version: 2009-05-11
- *
- * 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.
- *
- */
- (function (definition) {
- // Turn off strict mode for this function so we can assign to global.Q
- /*jshint strict: false, -W117*/
- // This file will function properly as a <script> tag, or a module
- // using CommonJS and NodeJS or RequireJS module formats. In
- // Common/Node/RequireJS, the module exports the Q API and when
- // executed as a simple <script>, it creates a Q global instead.
- // Montage Require
- if (typeof bootstrap === "function") {
- bootstrap("promise", definition);
- // CommonJS
- } else if (typeof exports === "object") {
- module.exports = definition();
- // RequireJS
- } else if (typeof define === "function" && define.amd) {
- define(definition);
- // SES (Secure EcmaScript)
- } else if (typeof ses !== "undefined") {
- if (!ses.ok()) {
- return;
- } else {
- ses.makeQ = definition;
- }
- // <script>
- } else {
- Q = definition();
- }
- })(function () {
- "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 in "allResolved"
- var noop = function () {};
- // Use the fastest possible means to execute a task in a future turn
- // of the event loop.
- var nextTick;
- if (typeof setImmediate === "function") {
- // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
- if (typeof window !== "undefined") {
- nextTick = setImmediate.bind(window);
- } else {
- nextTick = setImmediate;
- }
- } else if (typeof process !== "undefined" && process.nextTick) {
- // Node.js before 0.9. Note that some fake-Node environments, like the
- // Mocha test runner, introduce a `process` global without a `nextTick`.
- nextTick = process.nextTick;
- } else {
- (function () {
- // linked list of tasks (single, with head node)
- var head = {task: void 0, next: null};
- var tail = head;
- var maxPendingTicks = 2;
- var pendingTicks = 0;
- var queuedTasks = 0;
- var usedTicks = 0;
- var requestTick = void 0;
- function onTick() {
- // In case of multiple tasks ensure at least one subsequent tick
- // to handle remaining tasks in case one throws.
- --pendingTicks;
- if (++usedTicks >= maxPendingTicks) {
- // Amortize latency after thrown exceptions.
- usedTicks = 0;
- maxPendingTicks *= 4; // fast grow!
- var expectedTicks = queuedTasks && Math.min(
- queuedTasks - 1,
- maxPendingTicks
- );
- while (pendingTicks < expectedTicks) {
- ++pendingTicks;
- requestTick();
- }
- }
- while (queuedTasks) {
- --queuedTasks; // decrement here to ensure it's never negative
- head = head.next;
- var task = head.task;
- head.task = void 0;
- task();
- }
- usedTicks = 0;
- }
- nextTick = function (task) {
- tail = tail.next = {task: task, next: null};
- if (
- pendingTicks < ++queuedTasks &&
- pendingTicks < maxPendingTicks
- ) {
- ++pendingTicks;
- requestTick();
- }
- };
- if (typeof MessageChannel !== "undefined") {
- // modern browsers
- // http://www.nonblocking.io/2011/06/windownexttick.html
- var channel = new MessageChannel();
- channel.port1.onmessage = onTick;
- requestTick = function () {
- channel.port2.postMessage(0);
- };
- } else {
- // old browsers
- requestTick = function () {
- setTimeout(onTick, 0);
- };
- }
- })();
- }
- // 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
- function uncurryThis(f) {
- var call = Function.call;
- return function () {
- return call.apply(f, arguments);
- };
- }
- // This is equivalent, but slower:
- // uncurryThis = Function_bind.bind(Function_bind.call);
- // http://jsperf.com/uncurrythis
- 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;
- }
- );
- 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 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 object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
- var object_keys = Object.keys || function (object) {
- var keys = [];
- for (var key in object) {
- if (object_hasOwnProperty(object, key)) {
- keys.push(key);
- }
- }
- return keys;
- };
- var object_toString = uncurryThis(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
- Q.longStackJumpLimit = 1;
- var STACK_JUMP_SEPARATOR = "From previous event:";
- 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 &&
- typeof error === "object" &&
- error !== null &&
- error.stack &&
- error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
- ) {
- error.stack = filterStackString(error.stack) +
- "\n" + STACK_JUMP_SEPARATOR + "\n" +
- filterStackString(promise.stack);
- }
- }
- function filterStackString(stackString) {
- var lines = stackString.split("\n");
- var desiredLines = [];
- for (var i = 0; i < lines.length; ++i) {
- var line = lines[i];
- if (!isInternalFrame(line) && !isNodeFrame(line)) {
- desiredLines.push(line);
- }
- }
- return desiredLines.join("\n");
- }
- function isNodeFrame(stackLine) {
- return stackLine.indexOf("(module.js:") !== -1 ||
- stackLine.indexOf("(node.js:") !== -1;
- }
- function isInternalFrame(stackLine) {
- var pieces = /at .+ \((.*):(\d+):\d+\)/.exec(stackLine);
- if (!pieces) {
- return false;
- }
- var fileName = pieces[1];
- var lineNumber = pieces[2];
- return fileName === qFileName &&
- lineNumber >= qStartingLine &&
- lineNumber <= qEndingLine;
- }
- // 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[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;
- }
- }
- // end of shims
- // beginning of real work
- /**
- * Creates fulfilled promises from non-promises,
- * Passes Q promises through,
- * Coerces thenables to Q promises.
- */
- function Q(value) {
- return resolve(value);
- }
- /**
- * Performs a task in a future turn of the event loop.
- * @param {Function} task
- */
- Q.nextTick = nextTick;
- /**
- * Constructs a {promise, resolve} object.
- *
- * The resolver is a callback to invoke with a more resolved value for the
- * promise. To fulfill the promise, invoke the resolver with any value that is
- * not a function. To reject the promise, invoke the resolver with a rejection
- * object. To put the promise in the same state as another promise, invoke the
- * resolver with that other promise.
- */
- Q.defer = defer;
- function defer() {
- // if "pending" 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
- // 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 = [], progressListeners = [], resolvedPromise;
- var deferred = object_create(defer.prototype);
- var promise = object_create(makePromise.prototype);
- promise.promiseDispatch = function (resolve, op, operands) {
- var args = array_slice(arguments);
- if (pending) {
- pending.push(args);
- if (op === "when" && operands[1]) { // progress operand
- progressListeners.push(operands[1]);
- }
- } else {
- nextTick(function () {
- resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
- });
- }
- };
- promise.valueOf = function () {
- if (pending) {
- return promise;
- }
- var nearer = valueOf(resolvedPromise);
- if (isPromise(nearer)) {
- resolvedPromise = nearer; // shorten chain
- }
- return nearer;
- };
- 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
- );
- }
- // NOTE: we do the checks for `resolvedPromise` in each method, instead of
- // consolidating them into `become`, since otherwise we'd create new
- // promises with the lines `become(whatever(value))`. See e.g. GH-252.
- function become(promise) {
- resolvedPromise = promise;
- array_reduce(pending, function (undefined, pending) {
- nextTick(function () {
- promise.promiseDispatch.apply(promise, pending);
- });
- }, void 0);
- pending = void 0;
- progressListeners = void 0;
- }
- deferred.promise = promise;
- deferred.resolve = function (value) {
- if (resolvedPromise) {
- return;
- }
- become(resolve(value));
- };
- deferred.fulfill = function (value) {
- if (resolvedPromise) {
- return;
- }
- become(fulfill(value));
- };
- deferred.reject = function (reason) {
- if (resolvedPromise) {
- return;
- }
- become(reject(reason));
- };
- deferred.notify = function (progress) {
- if (resolvedPromise) {
- return;
- }
- array_reduce(progressListeners, function (undefined, progressListener) {
- nextTick(function () {
- progressListener(progress);
- });
- }, void 0);
- };
- return deferred;
- }
- /**
- * Creates a Node-style callback that will resolve or reject the deferred
- * promise.
- * @returns a nodeback
- */
- defer.prototype.makeNodeResolver = function () {
- var self = this;
- return function (error, value) {
- if (error) {
- self.reject(error);
- } else if (arguments.length > 2) {
- self.resolve(array_slice(arguments, 1));
- } else {
- self.resolve(value);
- }
- };
- };
- /**
- * @param resolver {Function} a function that returns nothing and accepts
- * 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 resolver
- */
- Q.promise = promise;
- function promise(resolver) {
- if (typeof resolver !== "function") {
- throw new TypeError("resolver must be a function.");
- }
- var deferred = defer();
- fcall(
- resolver,
- deferred.resolve,
- deferred.reject,
- deferred.notify
- ).fail(deferred.reject);
- return deferred.promise;
- }
- /**
- * Constructs a Promise with a promise descriptor object and optional fallback
- * function. The descriptor contains methods like when(rejected), get(name),
- * set(name, value), post(name, args), and delete(name), which all
- * return either a value, a promise for a value, or a rejection. The fallback
- * accepts the operation name, a resolver, and any further arguments that would
- * have been forwarded to the appropriate method above had a method been
- * provided with the proper name. The API makes no guarantees about the nature
- * of the returned object, apart from that it is usable whereever promises are
- * bought and sold.
- */
- Q.makePromise = makePromise;
- function makePromise(descriptor, fallback, valueOf, exception, isException) {
- if (fallback === void 0) {
- fallback = function (op) {
- return reject(new Error(
- "Promise does not support operation: " + op
- ));
- };
- }
- var promise = object_create(makePromise.prototype);
- promise.promiseDispatch = function (resolve, op, args) {
- var result;
- try {
- if (descriptor[op]) {
- result = descriptor[op].apply(promise, args);
- } else {
- result = fallback.call(promise, op, args);
- }
- } catch (exception) {
- result = reject(exception);
- }
- if (resolve) {
- resolve(result);
- }
- };
- if (valueOf) {
- promise.valueOf = valueOf;
- }
- if (isException) {
- promise.exception = exception;
- }
- return promise;
- }
- // provide thenables, CommonJS/Promises/A
- makePromise.prototype.then = function (fulfilled, rejected, progressed) {
- return when(this, fulfilled, rejected, progressed);
- };
- makePromise.prototype.thenResolve = function (value) {
- return when(this, function () { return value; });
- };
- makePromise.prototype.thenReject = function (reason) {
- return when(this, function () { throw reason; });
- };
- // Chainable methods
- array_reduce(
- [
- "isFulfilled", "isRejected", "isPending",
- "dispatch",
- "when", "spread",
- "get", "set", "del", "delete",
- "post", "send", "invoke",
- "keys",
- "fapply", "fcall", "fbind",
- "all", "allResolved",
- "timeout", "delay",
- "catch", "finally", "fail", "fin", "progress", "done",
- "nfcall", "nfapply", "nfbind", "denodeify", "nbind",
- "npost", "nsend", "ninvoke",
- "nodeify"
- ],
- function (undefined, name) {
- makePromise.prototype[name] = function () {
- return Q[name].apply(
- Q,
- [this].concat(array_slice(arguments))
- );
- };
- },
- void 0
- );
- makePromise.prototype.toSource = function () {
- return this.toString();
- };
- makePromise.prototype.toString = function () {
- return "[object Promise]";
- };
- /**
- * 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
- */
- Q.nearer = valueOf;
- function valueOf(value) {
- if (isPromise(value)) {
- return value.valueOf();
- }
- return value;
- }
- /**
- * @returns whether the given object is a promise.
- * Otherwise it is a fulfilled value.
- */
- Q.isPromise = isPromise;
- function isPromise(object) {
- return object && typeof object.promiseDispatch === "function";
- }
- Q.isPromiseAlike = isPromiseAlike;
- function isPromiseAlike(object) {
- return object && typeof object.then === "function";
- }
- /**
- * @returns whether the given object is a pending promise, meaning not
- * fulfilled or rejected.
- */
- Q.isPending = isPending;
- function isPending(object) {
- return !isFulfilled(object) && !isRejected(object);
- }
- /**
- * @returns whether the given object is a value or fulfilled
- * promise.
- */
- Q.isFulfilled = isFulfilled;
- function isFulfilled(object) {
- return !isPromiseAlike(valueOf(object));
- }
- /**
- * @returns whether the given object is a rejected promise.
- */
- Q.isRejected = isRejected;
- function isRejected(object) {
- object = valueOf(object);
- return isPromise(object) && "exception" in object;
- }
- // This promise library consumes exceptions thrown in handlers so they can be
- // handled by a subsequent promise. The exceptions get added to this array when
- // they are created, and removed when they are handled. Note that in ES6 or
- // shimmed environments, this would naturally be a `Set`.
- var unhandledReasons = Q.unhandledReasons = [];
- var unhandledRejections = [];
- var unhandledReasonsDisplayed = false;
- function displayUnhandledReasons() {
- if (
- !unhandledReasonsDisplayed &&
- typeof window !== "undefined" &&
- !window.Touch &&
- window.console
- ) {
- console.warn("[Q] Unhandled rejection reasons (should be empty):",
- unhandledReasons);
- }
- unhandledReasonsDisplayed = 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", 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);
- }
- }
- });
- }
- /**
- * Constructs a rejected promise.
- * @param reason value describing the failure
- */
- Q.reject = reject;
- function reject(reason) {
- var rejection = makePromise({
- "when": function (rejected) {
- // note that the error has been handled
- if (rejected) {
- var at = array_indexOf(unhandledRejections, this);
- if (at !== -1) {
- unhandledRejections.splice(at, 1);
- unhandledReasons.splice(at, 1);
- }
- }
- return rejected ? rejected(reason) : this;
- }
- }, function fallback() {
- return reject(reason);
- }, function valueOf() {
- return this;
- }, reason, true);
- // Note that the reason has not been handled.
- displayUnhandledReasons();
- unhandledRejections.push(rejection);
- unhandledReasons.push(reason);
- return rejection;
- }
- /**
- * Constructs a fulfilled promise for an immediate reference.
- * @param value immediate reference
- */
- Q.fulfill = fulfill;
- function fulfill(object) {
- return makePromise({
- "when": function () {
- return object;
- },
- "get": function (name) {
- return object[name];
- },
- "set": function (name, value) {
- object[name] = value;
- },
- "delete": function (name) {
- delete object[name];
- },
- "post": function (name, args) {
- // Mark Miller proposes that post with no name should apply a
- // promised function.
- if (name === null || name === void 0) {
- return object.apply(void 0, args);
- } else {
- return object[name].apply(object, args);
- }
- },
- "apply": function (thisP, args) {
- return object.apply(thisP, args);
- },
- "keys": function () {
- return object_keys(object);
- }
- }, void 0, function valueOf() {
- return object;
- });
- }
- /**
- * Constructs a promise for an immediate reference, passes promises through, or
- * coerces promises from different systems.
- * @param value immediate reference or promise
- */
- Q.resolve = resolve;
- function resolve(value) {
- // If the object is already a Promise, return it directly. This enables
- // the resolve function to both be used to created references from objects,
- // but to tolerably coerce non-promises to promises.
- if (isPromise(value)) {
- return value;
- }
- // 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.
- value = valueOf(value);
- // assimilate thenables, CommonJS/Promises/A+
- if (isPromiseAlike(value)) {
- return coerce(value);
- } else {
- return fulfill(value);
- }
- }
- /**
- * Converts thenables to Q promises.
- * @param promise thenable promise
- * @returns a Q promise
- */
- function coerce(promise) {
- var deferred = defer();
- nextTick(function () {
- try {
- promise.then(deferred.resolve, deferred.reject, deferred.notify);
- } catch (exception) {
- deferred.reject(exception);
- }
- });
- return deferred.promise;
- }
- /**
- * Annotates an object such that it will never be
- * transferred away from this process over any promise
- * communication channel.
- * @param object
- * @returns promise a wrapping of that object that
- * additionally responds to the "isDef" message
- * without a rejection.
- */
- Q.master = master;
- function master(object) {
- return makePromise({
- "isDef": function () {}
- }, function fallback(op, args) {
- return dispatch(object, op, args);
- }, function () {
- return valueOf(object);
- });
- }
- /**
- * Registers an observer on a promise.
- *
- * Guarantees:
- *
- * 1. that fulfilled and rejected will be called only once.
- * 2. that either the fulfilled callback or the rejected callback will be
- * 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 progressed function to be called on any progress notifications
- * @return promise for the return value from the invoked callback
- */
- Q.when = when;
- 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
- function _fulfilled(value) {
- try {
- return typeof fulfilled === "function" ? fulfilled(value) : value;
- } catch (exception) {
- return reject(exception);
- }
- }
- function _rejected(exception) {
- if (typeof rejected === "function") {
- makeStackTraceLong(exception, resolvedValue);
- try {
- return rejected(exception);
- } catch (newException) {
- return reject(newException);
- }
- }
- return reject(exception);
- }
- function _progressed(value) {
- return typeof progressed === "function" ? progressed(value) : value;
- }
- var resolvedValue = resolve(value);
- nextTick(function () {
- resolvedValue.promiseDispatch(function (value) {
- if (done) {
- return;
- }
- done = true;
- deferred.resolve(_fulfilled(value));
- }, "when", [function (exception) {
- if (done) {
- return;
- }
- done = true;
- deferred.resolve(_rejected(exception));
- }]);
- });
- // Progress propagator need to be attached in the current tick.
- resolvedValue.promiseDispatch(void 0, "when", [void 0, function (value) {
- var newValue;
- var threw = false;
- try {
- newValue = _progressed(value);
- } catch (e) {
- threw = true;
- if (Q.onerror) {
- Q.onerror(e);
- } else {
- throw e;
- }
- }
- if (!threw) {
- deferred.notify(newValue);
- }
- }]);
- return deferred.promise;
- }
- /**
- * 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.
- */
- Q.spread = spread;
- function spread(promise, fulfilled, rejected) {
- return when(promise, function (valuesOrPromises) {
- return all(valuesOrPromises).then(function (values) {
- return fulfilled.apply(void 0, values);
- }, rejected);
- }, rejected);
- }
- /**
- * 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.
- *
- * Decorates a generator function such that:
- * - it may yield promises
- * - execution will continue when that promise is fulfilled
- * - the value of the yield expression will be the fulfilled value
- * - it returns a promise for the return value (when the generator
- * stops iterating)
- * - the decorated function returns a promise for the return value
- * of the generator or the first rejected promise among those
- * yielded.
- * - if an error is thrown in the generator, it propagates through
- * every following yield until it is caught, or until it escapes
- * the generator function altogether, and is translated into a
- * 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
- *
- */
- Q.async = async;
- function async(makeGenerator) {
- return function () {
- // when verb is "send", arg is a value
- // when verb is "throw", arg is an exception
- function continuer(verb, arg) {
- var result;
- try {
- result = generator[verb](arg);
- } catch (exception) {
- if (isStopIteration(exception)) {
- return exception.value;
- } else {
- return reject(exception);
- }
- }
- return when(result, callback, errback);
- }
- var generator = makeGenerator.apply(this, arguments);
- var callback = continuer.bind(continuer, "send");
- var errback = continuer.bind(continuer, "throw");
- return callback();
- };
- }
- /**
- * 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);
- * })
- */
- Q["return"] = _return;
- 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.
- */
- Q.promised = promised;
- function promised(callback) {
- return function () {
- return spread([this, all(arguments)], function (self, args) {
- return callback.apply(self, args);
- });
- };
- }
- /**
- * 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
- */
- Q.dispatch = dispatch;
- function dispatch(object, op, args) {
- var deferred = defer();
- nextTick(function () {
- resolve(object).promiseDispatch(deferred.resolve, op, 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 "set(promise)".
- */
- Q.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.
- * @param object promise or immediate reference for target object
- * @param name name of property to get
- * @return promise for the property value
- */
- Q.get = dispatcher("get");
- /**
- * Sets the value of a property in a future turn.
- * @param object promise or immediate reference for object object
- * @param name name of property to set
- * @param value new value of property
- * @return promise for the return value
- */
- Q.set = dispatcher("set");
- /**
- * Deletes a property in a future turn.
- * @param object promise or immediate reference for target object
- * @param name name of property to delete
- * @return promise for the return value
- */
- Q["delete"] = // XXX experimental
- Q.del = dispatcher("delete");
- /**
- * Invokes a method in a future turn.
- * @param object promise or immediate reference for target object
- * @param name name of method to invoke
- * @param value a value to post, typically an array of
- * invocation arguments for promises that
- * are ultimately backed with `resolve` values,
- * as opposed to those backed with URLs
- * wherein the posted value can be any
- * JSON serializable object.
- * @return promise for the return value
- */
- // bound locally because it is used by other methods
- var post = Q.post = dispatcher("post");
- /**
- * Invokes a method in a future turn.
- * @param object promise or immediate reference for target object
- * @param name name of method to invoke
- * @param ...args array of invocation arguments
- * @return promise for the return value
- */
- Q.send = send;
- Q.invoke = send; // synonyms
- function send(value, name) {
- var args = array_slice(arguments, 2);
- return post(value, name, args);
- }
- /**
- * Applies the promised function in a future turn.
- * @param object promise or immediate reference for target function
- * @param args array of application arguments
- */
- Q.fapply = fapply;
- function fapply(value, args) {
- return dispatch(value, "apply", [void 0, args]);
- }
- /**
- * Calls the promised function in a future turn.
- * @param object promise or immediate reference for target function
- * @param ...args array of application arguments
- */
- Q["try"] = fcall; // XXX experimental
- Q.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 ...args array of application arguments
- */
- Q.fbind = fbind;
- function fbind(value) {
- var args = array_slice(arguments, 1);
- return function fbound() {
- var allArgs = args.concat(array_slice(arguments));
- return dispatch(value, "apply", [this, allArgs]);
- };
- }
- /**
- * Requests the names of the owned properties of a promised
- * object in a future turn.
- * @param object promise or immediate reference for target object
- * @return promise for the keys of the eventually resolved object
- */
- Q.keys = dispatcher("keys");
- /**
- * Turns an array of promises into a promise for an array. If any of
- * the promises gets rejected, the whole array is rejected immediately.
- * @param {Array*} an array (or promise for an array) of values (or
- * promises for values)
- * @returns a promise for an array of the corresponding values
- */
- // By Mark Miller
- // http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
- Q.all = all;
- function all(promises) {
- return when(promises, function (promises) {
- var countDown = 0;
- var deferred = defer();
- array_reduce(promises, function (undefined, promise, index) {
- if (isFulfilled(promise)) {
- promises[index] = valueOf(promise);
- } else {
- ++countDown;
- when(promise, function (value) {
- promises[index] = value;
- if (--countDown === 0) {
- deferred.resolve(promises);
- }
- }, deferred.reject);
- }
- }, void 0);
- if (countDown === 0) {
- deferred.resolve(promises);
- }
- return deferred.promise;
- });
- }
- /**
- * 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
- */
- Q.allResolved = allResolved;
- function allResolved(promises) {
- return when(promises, function (promises) {
- promises = array_map(promises, resolve);
- return when(all(array_map(promises, function (promise) {
- return when(promise, noop, noop);
- })), function () {
- return promises;
- });
- });
- }
- /**
- * Captures the failure of a promise, giving an oportunity to recover
- * with a callback. If the given promise is fulfilled, the returned
- * promise is fulfilled.
- * @param {Any*} promise for something
- * @param {Function} callback to fulfill the returned promise if the
- * given promise is rejected
- * @returns a promise for the return value of the callback
- */
- Q["catch"] = // XXX experimental
- Q.fail = fail;
- 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
- */
- Q.progress = progress;
- function progress(promise, progressed) {
- return when(promise, void 0, void 0, progressed);
- }
- /**
- * Provides an opportunity to observe the rejection of a promise,
- * regardless of whether the promise is fulfilled or rejected. Forwards
- * the resolution to the returned promise when the callback is done.
- * The callback can return a promise to defer completion.
- * @param {Any*} promise
- * @param {Function} callback to observe the resolution of the given
- * promise, takes no arguments.
- * @returns a promise for the resolution of the given promise when
- * ``fin`` is done.
- */
- Q["finally"] = // XXX experimental
- Q.fin = fin;
- function fin(promise, callback) {
- return when(promise, function (value) {
- return when(callback(), function () {
- return value;
- });
- }, function (exception) {
- return when(callback(), function () {
- return reject(exception);
- });
- });
- }
- /**
- * Terminates a chain of promises, forcing rejections to be
- * thrown as exceptions.
- * @param {Any*} promise at the end of a chain of promises
- * @returns nothing
- */
- Q.done = done;
- function done(promise, fulfilled, rejected, progress) {
- var onUnhandledError = function (error) {
- // forward to a future turn so that ``when``
- // does not catch it and turn it into a rejection.
- nextTick(function () {
- makeStackTraceLong(error, promise);
- if (Q.onerror) {
- Q.onerror(error);
- } else {
- throw error;
- }
- });
- };
- // Avoid unnecessary `nextTick`ing via an unnecessary `when`.
- var promiseToHandle = fulfilled || rejected || progress ?
- when(promise, fulfilled, rejected, progress) :
- promise;
- if (typeof process === "object" && process && process.domain) {
- onUnhandledError = process.domain.bind(onUnhandledError);
- }
- fail(promiseToHandle, onUnhandledError);
- }
- /**
- * Causes a promise to be rejected if it does not get fulfilled before
- * some milliseconds time out.
- * @param {Any*} promise
- * @param {Number} milliseconds timeout
- * @param {String} custom error message (optional)
- * @returns a promise for the resolution of the given promise if it is
- * fulfilled before the timeout, otherwise rejected.
- */
- Q.timeout = timeout;
- function timeout(promise, ms, msg) {
- var deferred = defer();
- var timeoutId = setTimeout(function () {
- deferred.reject(new Error(msg || "Timed out after " + ms + " ms"));
- }, ms);
- when(promise, function (value) {
- clearTimeout(timeoutId);
- deferred.resolve(value);
- }, function (exception) {
- clearTimeout(timeoutId);
- deferred.reject(exception);
- }, deferred.notify);
- return deferred.promise;
- }
- /**
- * Returns a promise for the given value (or promised value) after some
- * milliseconds.
- * @param {Any*} promise
- * @param {Number} milliseconds
- * @returns a promise for the resolution of the given promise after some
- * time has elapsed.
- */
- Q.delay = delay;
- function delay(promise, timeout) {
- if (timeout === void 0) {
- timeout = promise;
- promise = void 0;
- }
- var deferred = defer();
- when(promise, undefined, undefined, deferred.notify);
- setTimeout(function () {
- deferred.resolve(promise);
- }, timeout);
- return deferred.promise;
- }
- /**
- * Passes a continuation to a Node function, which is called with the given
- * arguments provided as an array, and returns a promise.
- *
- * Q.nfapply(FS.readFile, [__filename])
- * .then(function (content) {
- * })
- *
- */
- Q.nfapply = nfapply;
- function nfapply(callback, args) {
- var nodeArgs = array_slice(args);
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- fapply(callback, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- }
- /**
- * Passes a continuation to a Node function, which is called with the given
- * arguments provided individually, and returns a promise.
- *
- * Q.nfcall(FS.readFile, __filename)
- * .then(function (content) {
- * })
- *
- */
- Q.nfcall = nfcall;
- function nfcall(callback/*, ...args */) {
- var nodeArgs = array_slice(arguments, 1);
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- fapply(callback, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- }
- /**
- * Wraps a NodeJS continuation passing function and returns an equivalent
- * version that returns a promise.
- *
- * Q.nfbind(FS.readFile, __filename)("utf-8")
- * .then(console.log)
- * .done()
- *
- */
- Q.nfbind = nfbind;
- Q.denodeify = Q.nfbind; // synonyms
- function nfbind(callback/*, ...args */) {
- var baseArgs = array_slice(arguments, 1);
- return function () {
- var nodeArgs = baseArgs.concat(array_slice(arguments));
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- fapply(callback, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- };
- }
- Q.nbind = nbind;
- function nbind(callback, thisArg /*, ... args*/) {
- var baseArgs = array_slice(arguments, 2);
- return function () {
- var nodeArgs = baseArgs.concat(array_slice(arguments));
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- function bound() {
- return callback.apply(thisArg, arguments);
- }
- fapply(bound, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- };
- }
- /**
- * 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
- */
- Q.npost = npost;
- function npost(object, name, args) {
- var nodeArgs = array_slice(args || []);
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- post(object, name, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- }
- /**
- * 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
- */
- Q.nsend = nsend;
- Q.ninvoke = Q.nsend; // synonyms
- function nsend(object, name /*, ...args*/) {
- var nodeArgs = array_slice(arguments, 2);
- var deferred = defer();
- nodeArgs.push(deferred.makeNodeResolver());
- post(object, name, nodeArgs).fail(deferred.reject);
- return deferred.promise;
- }
- Q.nodeify = nodeify;
- function nodeify(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();
- return Q;
- });
|