source: Dev/trunk/src/node_modules/q/q.js @ 484

Last change on this file since 484 was 484, checked in by hendrikvanantwerpen, 11 years ago

Commit node_modules, to make checkouts and builds more deterministic.

File size: 51.6 KB
Line 
1// vim:ts=4:sts=4:sw=4:
2/*!
3 *
4 * Copyright 2009-2012 Kris Kowal under the terms of the MIT
5 * license found at http://github.com/kriskowal/q/raw/master/LICENSE
6 *
7 * With parts by Tyler Close
8 * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
9 * at http://www.opensource.org/licenses/mit-license.html
10 * Forked at ref_send.js version: 2009-05-11
11 *
12 * With parts by Mark Miller
13 * Copyright (C) 2011 Google Inc.
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *
27 */
28
29(function (definition) {
30    // Turn off strict mode for this function so we can assign to global.Q
31    /* jshint strict: false */
32
33    // This file will function properly as a <script> tag, or a module
34    // using CommonJS and NodeJS or RequireJS module formats.  In
35    // Common/Node/RequireJS, the module exports the Q API and when
36    // executed as a simple <script>, it creates a Q global instead.
37
38    // Montage Require
39    if (typeof bootstrap === "function") {
40        bootstrap("promise", definition);
41
42    // CommonJS
43    } else if (typeof exports === "object") {
44        module.exports = definition();
45
46    // RequireJS
47    } else if (typeof define === "function" && define.amd) {
48        define(definition);
49
50    // SES (Secure EcmaScript)
51    } else if (typeof ses !== "undefined") {
52        if (!ses.ok()) {
53            return;
54        } else {
55            ses.makeQ = definition;
56        }
57
58    // <script>
59    } else {
60        Q = definition();
61    }
62
63})(function () {
64"use strict";
65
66var hasStacks = false;
67try {
68    throw new Error();
69} catch (e) {
70    hasStacks = !!e.stack;
71}
72
73// All code after this point will be filtered from stack traces reported
74// by Q.
75var qStartingLine = captureLine();
76var qFileName;
77
78// shims
79
80// used for fallback in "allResolved"
81var noop = function () {};
82
83// Use the fastest possible means to execute a task in a future turn
84// of the event loop.
85var nextTick =(function () {
86    // linked list of tasks (single, with head node)
87    var head = {task: void 0, next: null};
88    var tail = head;
89    var flushing = false;
90    var requestTick = void 0;
91    var isNodeJS = false;
92
93    function flush() {
94        while (head.next) {
95            head = head.next;
96            var task = head.task;
97            head.task = void 0;
98            var domain = head.domain;
99
100            if (domain) {
101                head.domain = void 0;
102                domain.enter();
103            }
104
105            try {
106                task();
107
108            } catch (e) {
109                if (isNodeJS) {
110                    // In node, uncaught exceptions are considered fatal errors.
111                    // Re-throw them synchronously to interrupt flushing!
112
113                    // Ensure continuation if the uncaught exception is suppressed
114                    // listening "uncaughtException" events (as domains does).
115                    // Continue in next event to avoid tick recursion.
116                    domain && domain.exit();
117                    setTimeout(flush, 0);
118                    domain && domain.enter();
119
120                    throw e;
121
122                } else {
123                    // In browsers, uncaught exceptions are not fatal.
124                    // Re-throw them asynchronously to avoid slow-downs.
125                    setTimeout(function() {
126                       throw e;
127                    }, 0);
128                }
129            }
130
131            if (domain) {
132                domain.exit();
133            }
134        }
135
136        flushing = false;
137    }
138
139    nextTick = function (task) {
140        tail = tail.next = {
141            task: task,
142            domain: isNodeJS && process.domain,
143            next: null
144        };
145
146        if (!flushing) {
147            flushing = true;
148            requestTick();
149        }
150    };
151
152    if (typeof process !== "undefined" && process.nextTick) {
153        // Node.js before 0.9. Note that some fake-Node environments, like the
154        // Mocha test runner, introduce a `process` global without a `nextTick`.
155        isNodeJS = true;
156
157        requestTick = function () {
158            process.nextTick(flush);
159        };
160
161    } else if (typeof setImmediate === "function") {
162        // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
163        if (typeof window !== "undefined") {
164            requestTick = setImmediate.bind(window, flush);
165        } else {
166            requestTick = function () {
167                setImmediate(flush);
168            };
169        }
170
171    } else if (typeof MessageChannel !== "undefined") {
172        // modern browsers
173        // http://www.nonblocking.io/2011/06/windownexttick.html
174        var channel = new MessageChannel();
175        channel.port1.onmessage = flush;
176        requestTick = function () {
177            channel.port2.postMessage(0);
178        };
179
180    } else {
181        // old browsers
182        requestTick = function () {
183            setTimeout(flush, 0);
184        };
185    }
186
187    return nextTick;
188})();
189
190// Attempt to make generics safe in the face of downstream
191// modifications.
192// There is no situation where this is necessary.
193// If you need a security guarantee, these primordials need to be
194// deeply frozen anyway, and if you don’t need a security guarantee,
195// this is just plain paranoid.
196// However, this does have the nice side-effect of reducing the size
197// of the code by reducing x.call() to merely x(), eliminating many
198// hard-to-minify characters.
199// See Mark Miller’s explanation of what this does.
200// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
201function uncurryThis(f) {
202    var call = Function.call;
203    return function () {
204        return call.apply(f, arguments);
205    };
206}
207// This is equivalent, but slower:
208// uncurryThis = Function_bind.bind(Function_bind.call);
209// http://jsperf.com/uncurrythis
210
211var array_slice = uncurryThis(Array.prototype.slice);
212
213var array_reduce = uncurryThis(
214    Array.prototype.reduce || function (callback, basis) {
215        var index = 0,
216            length = this.length;
217        // concerning the initial value, if one is not provided
218        if (arguments.length === 1) {
219            // seek to the first value in the array, accounting
220            // for the possibility that is is a sparse array
221            do {
222                if (index in this) {
223                    basis = this[index++];
224                    break;
225                }
226                if (++index >= length) {
227                    throw new TypeError();
228                }
229            } while (1);
230        }
231        // reduce
232        for (; index < length; index++) {
233            // account for the possibility that the array is sparse
234            if (index in this) {
235                basis = callback(basis, this[index], index);
236            }
237        }
238        return basis;
239    }
240);
241
242var array_indexOf = uncurryThis(
243    Array.prototype.indexOf || function (value) {
244        // not a very good shim, but good enough for our one use of it
245        for (var i = 0; i < this.length; i++) {
246            if (this[i] === value) {
247                return i;
248            }
249        }
250        return -1;
251    }
252);
253
254var array_map = uncurryThis(
255    Array.prototype.map || function (callback, thisp) {
256        var self = this;
257        var collect = [];
258        array_reduce(self, function (undefined, value, index) {
259            collect.push(callback.call(thisp, value, index, self));
260        }, void 0);
261        return collect;
262    }
263);
264
265var object_create = Object.create || function (prototype) {
266    function Type() { }
267    Type.prototype = prototype;
268    return new Type();
269};
270
271var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
272
273var object_keys = Object.keys || function (object) {
274    var keys = [];
275    for (var key in object) {
276        if (object_hasOwnProperty(object, key)) {
277            keys.push(key);
278        }
279    }
280    return keys;
281};
282
283var object_toString = uncurryThis(Object.prototype.toString);
284
285function isObject(value) {
286    return value === Object(value);
287}
288
289// generator related shims
290
291// FIXME: Remove this function once ES6 generators are in SpiderMonkey.
292function isStopIteration(exception) {
293    return (
294        object_toString(exception) === "[object StopIteration]" ||
295        exception instanceof QReturnValue
296    );
297}
298
299// FIXME: Remove this helper and Q.return once ES6 generators are in
300// SpiderMonkey.
301var QReturnValue;
302if (typeof ReturnValue !== "undefined") {
303    QReturnValue = ReturnValue;
304} else {
305    QReturnValue = function (value) {
306        this.value = value;
307    };
308}
309
310// Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only
311// engine that has a deployed base of browsers that support generators.
312// However, SM's generators use the Python-inspired semantics of
313// outdated ES6 drafts.  We would like to support ES6, but we'd also
314// like to make it possible to use generators in deployed browsers, so
315// we also support Python-style generators.  At some point we can remove
316// this block.
317var hasES6Generators;
318try {
319    /* jshint evil: true, nonew: false */
320    new Function("(function* (){ yield 1; })");
321    hasES6Generators = true;
322} catch (e) {
323    hasES6Generators = false;
324}
325
326// long stack traces
327
328var STACK_JUMP_SEPARATOR = "From previous event:";
329
330function makeStackTraceLong(error, promise) {
331    // If possible, transform the error stack trace by removing Node and Q
332    // cruft, then concatenating with the stack trace of `promise`. See #57.
333    if (hasStacks &&
334        promise.stack &&
335        typeof error === "object" &&
336        error !== null &&
337        error.stack &&
338        error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
339    ) {
340        var stacks = [];
341        for (var p = promise; !!p; p = p.source) {
342            if (p.stack) {
343                stacks.unshift(p.stack);
344            }
345        }
346        stacks.unshift(error.stack);
347
348        var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n");
349        error.stack = filterStackString(concatedStacks);
350    }
351}
352
353function filterStackString(stackString) {
354    var lines = stackString.split("\n");
355    var desiredLines = [];
356    for (var i = 0; i < lines.length; ++i) {
357        var line = lines[i];
358
359        if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
360            desiredLines.push(line);
361        }
362    }
363    return desiredLines.join("\n");
364}
365
366function isNodeFrame(stackLine) {
367    return stackLine.indexOf("(module.js:") !== -1 ||
368           stackLine.indexOf("(node.js:") !== -1;
369}
370
371function getFileNameAndLineNumber(stackLine) {
372    // Named functions: "at functionName (filename:lineNumber:columnNumber)"
373    // In IE10 function name can have spaces ("Anonymous function") O_o
374    var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
375    if (attempt1) {
376        return [attempt1[1], Number(attempt1[2])];
377    }
378
379    // Anonymous functions: "at filename:lineNumber:columnNumber"
380    var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
381    if (attempt2) {
382        return [attempt2[1], Number(attempt2[2])];
383    }
384
385    // Firefox style: "function@filename:lineNumber or @filename:lineNumber"
386    var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
387    if (attempt3) {
388        return [attempt3[1], Number(attempt3[2])];
389    }
390}
391
392function isInternalFrame(stackLine) {
393    var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);
394
395    if (!fileNameAndLineNumber) {
396        return false;
397    }
398
399    var fileName = fileNameAndLineNumber[0];
400    var lineNumber = fileNameAndLineNumber[1];
401
402    return fileName === qFileName &&
403        lineNumber >= qStartingLine &&
404        lineNumber <= qEndingLine;
405}
406
407// discover own file name and line number range for filtering stack
408// traces
409function captureLine() {
410    if (!hasStacks) {
411        return;
412    }
413
414    try {
415        throw new Error();
416    } catch (e) {
417        var lines = e.stack.split("\n");
418        var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2];
419        var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
420        if (!fileNameAndLineNumber) {
421            return;
422        }
423
424        qFileName = fileNameAndLineNumber[0];
425        return fileNameAndLineNumber[1];
426    }
427}
428
429function deprecate(callback, name, alternative) {
430    return function () {
431        if (typeof console !== "undefined" &&
432            typeof console.warn === "function") {
433            console.warn(name + " is deprecated, use " + alternative +
434                         " instead.", new Error("").stack);
435        }
436        return callback.apply(callback, arguments);
437    };
438}
439
440// end of shims
441// beginning of real work
442
443/**
444 * Creates fulfilled promises from non-thenables,
445 * Passes Q promises through,
446 * Coerces other thenables to Q promises.
447 */
448function Q(value) {
449    return resolve(value);
450}
451
452/**
453 * Performs a task in a future turn of the event loop.
454 * @param {Function} task
455 */
456Q.nextTick = nextTick;
457
458/**
459 * Controls whether or not long stack traces will be on
460 */
461Q.longStackSupport = false;
462
463/**
464 * Constructs a {promise, resolve, reject} object.
465 *
466 * `resolve` is a callback to invoke with a more resolved value for the
467 * promise. To fulfill the promise, invoke `resolve` with any value that is
468 * not a thenable. To reject the promise, invoke `resolve` with a rejected
469 * thenable, or invoke `reject` with the reason directly. To resolve the
470 * promise to another thenable, thus putting it in the same state, invoke
471 * `resolve` with that other thenable.
472 */
473Q.defer = defer;
474function defer() {
475    // if "messages" is an "Array", that indicates that the promise has not yet
476    // been resolved.  If it is "undefined", it has been resolved.  Each
477    // element of the messages array is itself an array of complete arguments to
478    // forward to the resolved promise.  We coerce the resolution value to a
479    // promise using the `resolve` function because it handles both fully
480    // non-thenable values and other thenables gracefully.
481    var messages = [], progressListeners = [], resolvedPromise;
482
483    var deferred = object_create(defer.prototype);
484    var promise = object_create(Promise.prototype);
485
486    promise.promiseDispatch = function (resolve, op, operands) {
487        var args = array_slice(arguments);
488        if (messages) {
489            messages.push(args);
490            if (op === "when" && operands[1]) { // progress operand
491                progressListeners.push(operands[1]);
492            }
493        } else {
494            nextTick(function () {
495                resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
496            });
497        }
498    };
499
500    // XXX deprecated
501    promise.valueOf = deprecate(function () {
502        if (messages) {
503            return promise;
504        }
505        var nearerValue = nearer(resolvedPromise);
506        if (isPromise(nearerValue)) {
507            resolvedPromise = nearerValue; // shorten chain
508        }
509        return nearerValue;
510    }, "valueOf", "inspect");
511
512    promise.inspect = function () {
513        if (!resolvedPromise) {
514            return { state: "pending" };
515        }
516        return resolvedPromise.inspect();
517    };
518
519    if (Q.longStackSupport && hasStacks) {
520        try {
521            throw new Error();
522        } catch (e) {
523            // NOTE: don't try to use `Error.captureStackTrace` or transfer the
524            // accessor around; that causes memory leaks as per GH-111. Just
525            // reify the stack trace as a string ASAP.
526            //
527            // At the same time, cut off the first line; it's always just
528            // "[object Promise]\n", as per the `toString`.
529            promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1);
530        }
531    }
532
533    // NOTE: we do the checks for `resolvedPromise` in each method, instead of
534    // consolidating them into `become`, since otherwise we'd create new
535    // promises with the lines `become(whatever(value))`. See e.g. GH-252.
536
537    function become(newPromise) {
538        resolvedPromise = newPromise;
539        promise.source = newPromise;
540
541        array_reduce(messages, function (undefined, message) {
542            nextTick(function () {
543                newPromise.promiseDispatch.apply(newPromise, message);
544            });
545        }, void 0);
546
547        messages = void 0;
548        progressListeners = void 0;
549    }
550
551    deferred.promise = promise;
552    deferred.resolve = function (value) {
553        if (resolvedPromise) {
554            return;
555        }
556
557        become(resolve(value));
558    };
559
560    deferred.fulfill = function (value) {
561        if (resolvedPromise) {
562            return;
563        }
564
565        become(fulfill(value));
566    };
567    deferred.reject = function (reason) {
568        if (resolvedPromise) {
569            return;
570        }
571
572        become(reject(reason));
573    };
574    deferred.notify = function (progress) {
575        if (resolvedPromise) {
576            return;
577        }
578
579        array_reduce(progressListeners, function (undefined, progressListener) {
580            nextTick(function () {
581                progressListener(progress);
582            });
583        }, void 0);
584    };
585
586    return deferred;
587}
588
589/**
590 * Creates a Node-style callback that will resolve or reject the deferred
591 * promise.
592 * @returns a nodeback
593 */
594defer.prototype.makeNodeResolver = function () {
595    var self = this;
596    return function (error, value) {
597        if (error) {
598            self.reject(error);
599        } else if (arguments.length > 2) {
600            self.resolve(array_slice(arguments, 1));
601        } else {
602            self.resolve(value);
603        }
604    };
605};
606
607/**
608 * @param resolver {Function} a function that returns nothing and accepts
609 * the resolve, reject, and notify functions for a deferred.
610 * @returns a promise that may be resolved with the given resolve and reject
611 * functions, or rejected by a thrown exception in resolver
612 */
613Q.promise = promise;
614function promise(resolver) {
615    if (typeof resolver !== "function") {
616        throw new TypeError("resolver must be a function.");
617    }
618
619    var deferred = defer();
620    fcall(
621        resolver,
622        deferred.resolve,
623        deferred.reject,
624        deferred.notify
625    ).fail(deferred.reject);
626    return deferred.promise;
627}
628
629/**
630 * Constructs a Promise with a promise descriptor object and optional fallback
631 * function.  The descriptor contains methods like when(rejected), get(name),
632 * set(name, value), post(name, args), and delete(name), which all
633 * return either a value, a promise for a value, or a rejection.  The fallback
634 * accepts the operation name, a resolver, and any further arguments that would
635 * have been forwarded to the appropriate method above had a method been
636 * provided with the proper name.  The API makes no guarantees about the nature
637 * of the returned object, apart from that it is usable whereever promises are
638 * bought and sold.
639 */
640Q.makePromise = Promise;
641function Promise(descriptor, fallback, inspect) {
642    if (fallback === void 0) {
643        fallback = function (op) {
644            return reject(new Error(
645                "Promise does not support operation: " + op
646            ));
647        };
648    }
649    if (inspect === void 0) {
650        inspect = function () {
651            return {state: "unknown"};
652        };
653    }
654
655    var promise = object_create(Promise.prototype);
656
657    promise.promiseDispatch = function (resolve, op, args) {
658        var result;
659        try {
660            if (descriptor[op]) {
661                result = descriptor[op].apply(promise, args);
662            } else {
663                result = fallback.call(promise, op, args);
664            }
665        } catch (exception) {
666            result = reject(exception);
667        }
668        if (resolve) {
669            resolve(result);
670        }
671    };
672
673    promise.inspect = inspect;
674
675    // XXX deprecated `valueOf` and `exception` support
676    if (inspect) {
677        var inspected = inspect();
678        if (inspected.state === "rejected") {
679            promise.exception = inspected.reason;
680        }
681
682        promise.valueOf = deprecate(function () {
683            var inspected = inspect();
684            if (inspected.state === "pending" ||
685                inspected.state === "rejected") {
686                return promise;
687            }
688            return inspected.value;
689        });
690    }
691
692    return promise;
693}
694
695Promise.prototype.then = function (fulfilled, rejected, progressed) {
696    var self = this;
697    var deferred = defer();
698    var done = false;   // ensure the untrusted promise makes at most a
699                        // single call to one of the callbacks
700
701    function _fulfilled(value) {
702        try {
703            return typeof fulfilled === "function" ? fulfilled(value) : value;
704        } catch (exception) {
705            return reject(exception);
706        }
707    }
708
709    function _rejected(exception) {
710        if (typeof rejected === "function") {
711            makeStackTraceLong(exception, self);
712            try {
713                return rejected(exception);
714            } catch (newException) {
715                return reject(newException);
716            }
717        }
718        return reject(exception);
719    }
720
721    function _progressed(value) {
722        return typeof progressed === "function" ? progressed(value) : value;
723    }
724
725    nextTick(function () {
726        self.promiseDispatch(function (value) {
727            if (done) {
728                return;
729            }
730            done = true;
731
732            deferred.resolve(_fulfilled(value));
733        }, "when", [function (exception) {
734            if (done) {
735                return;
736            }
737            done = true;
738
739            deferred.resolve(_rejected(exception));
740        }]);
741    });
742
743    // Progress propagator need to be attached in the current tick.
744    self.promiseDispatch(void 0, "when", [void 0, function (value) {
745        var newValue;
746        var threw = false;
747        try {
748            newValue = _progressed(value);
749        } catch (e) {
750            threw = true;
751            if (Q.onerror) {
752                Q.onerror(e);
753            } else {
754                throw e;
755            }
756        }
757
758        if (!threw) {
759            deferred.notify(newValue);
760        }
761    }]);
762
763    return deferred.promise;
764};
765
766Promise.prototype.thenResolve = function (value) {
767    return when(this, function () { return value; });
768};
769
770Promise.prototype.thenReject = function (reason) {
771    return when(this, function () { throw reason; });
772};
773
774// Chainable methods
775array_reduce(
776    [
777        "isFulfilled", "isRejected", "isPending",
778        "dispatch",
779        "when", "spread",
780        "get", "set", "del", "delete",
781        "post", "send", "mapply", "invoke", "mcall",
782        "keys",
783        "fapply", "fcall", "fbind",
784        "all", "allResolved",
785        "timeout", "delay",
786        "catch", "finally", "fail", "fin", "progress", "done",
787        "nfcall", "nfapply", "nfbind", "denodeify", "nbind",
788        "npost", "nsend", "nmapply", "ninvoke", "nmcall",
789        "nodeify"
790    ],
791    function (undefined, name) {
792        Promise.prototype[name] = function () {
793            return Q[name].apply(
794                Q,
795                [this].concat(array_slice(arguments))
796            );
797        };
798    },
799    void 0
800);
801
802Promise.prototype.toSource = function () {
803    return this.toString();
804};
805
806Promise.prototype.toString = function () {
807    return "[object Promise]";
808};
809
810/**
811 * If an object is not a promise, it is as "near" as possible.
812 * If a promise is rejected, it is as "near" as possible too.
813 * If it’s a fulfilled promise, the fulfillment value is nearer.
814 * If it’s a deferred promise and the deferred has been resolved, the
815 * resolution is "nearer".
816 * @param object
817 * @returns most resolved (nearest) form of the object
818 */
819
820// XXX should we re-do this?
821Q.nearer = nearer;
822function nearer(value) {
823    if (isPromise(value)) {
824        var inspected = value.inspect();
825        if (inspected.state === "fulfilled") {
826            return inspected.value;
827        }
828    }
829    return value;
830}
831
832/**
833 * @returns whether the given object is a promise.
834 * Otherwise it is a fulfilled value.
835 */
836Q.isPromise = isPromise;
837function isPromise(object) {
838    return isObject(object) &&
839        typeof object.promiseDispatch === "function" &&
840        typeof object.inspect === "function";
841}
842
843Q.isPromiseAlike = isPromiseAlike;
844function isPromiseAlike(object) {
845    return isObject(object) && typeof object.then === "function";
846}
847
848/**
849 * @returns whether the given object is a pending promise, meaning not
850 * fulfilled or rejected.
851 */
852Q.isPending = isPending;
853function isPending(object) {
854    return isPromise(object) && object.inspect().state === "pending";
855}
856
857/**
858 * @returns whether the given object is a value or fulfilled
859 * promise.
860 */
861Q.isFulfilled = isFulfilled;
862function isFulfilled(object) {
863    return !isPromise(object) || object.inspect().state === "fulfilled";
864}
865
866/**
867 * @returns whether the given object is a rejected promise.
868 */
869Q.isRejected = isRejected;
870function isRejected(object) {
871    return isPromise(object) && object.inspect().state === "rejected";
872}
873
874//// BEGIN UNHANDLED REJECTION TRACKING
875
876// This promise library consumes exceptions thrown in handlers so they can be
877// handled by a subsequent promise.  The exceptions get added to this array when
878// they are created, and removed when they are handled.  Note that in ES6 or
879// shimmed environments, this would naturally be a `Set`.
880var unhandledReasons = [];
881var unhandledRejections = [];
882var unhandledReasonsDisplayed = false;
883var trackUnhandledRejections = true;
884function displayUnhandledReasons() {
885    if (
886        !unhandledReasonsDisplayed &&
887        typeof window !== "undefined" &&
888        !window.Touch &&
889        window.console
890    ) {
891        console.warn("[Q] Unhandled rejection reasons (should be empty):",
892                     unhandledReasons);
893    }
894
895    unhandledReasonsDisplayed = true;
896}
897
898function logUnhandledReasons() {
899    for (var i = 0; i < unhandledReasons.length; i++) {
900        var reason = unhandledReasons[i];
901        if (reason && typeof reason.stack !== "undefined") {
902            console.warn("Unhandled rejection reason:", reason.stack);
903        } else {
904            console.warn("Unhandled rejection reason (no stack):", reason);
905        }
906    }
907}
908
909function resetUnhandledRejections() {
910    unhandledReasons.length = 0;
911    unhandledRejections.length = 0;
912    unhandledReasonsDisplayed = false;
913
914    if (!trackUnhandledRejections) {
915        trackUnhandledRejections = true;
916
917        // Show unhandled rejection reasons if Node exits without handling an
918        // outstanding rejection.  (Note that Browserify presently produces a
919        // `process` global without the `EventEmitter` `on` method.)
920        if (typeof process !== "undefined" && process.on) {
921            process.on("exit", logUnhandledReasons);
922        }
923    }
924}
925
926function trackRejection(promise, reason) {
927    if (!trackUnhandledRejections) {
928        return;
929    }
930
931    unhandledRejections.push(promise);
932    unhandledReasons.push(reason);
933    displayUnhandledReasons();
934}
935
936function untrackRejection(promise) {
937    if (!trackUnhandledRejections) {
938        return;
939    }
940
941    var at = array_indexOf(unhandledRejections, promise);
942    if (at !== -1) {
943        unhandledRejections.splice(at, 1);
944        unhandledReasons.splice(at, 1);
945    }
946}
947
948Q.resetUnhandledRejections = resetUnhandledRejections;
949
950Q.getUnhandledReasons = function () {
951    // Make a copy so that consumers can't interfere with our internal state.
952    return unhandledReasons.slice();
953};
954
955Q.stopUnhandledRejectionTracking = function () {
956    resetUnhandledRejections();
957    if (typeof process !== "undefined" && process.on) {
958        process.removeListener("exit", logUnhandledReasons);
959    }
960    trackUnhandledRejections = false;
961};
962
963resetUnhandledRejections();
964
965//// END UNHANDLED REJECTION TRACKING
966
967/**
968 * Constructs a rejected promise.
969 * @param reason value describing the failure
970 */
971Q.reject = reject;
972function reject(reason) {
973    var rejection = Promise({
974        "when": function (rejected) {
975            // note that the error has been handled
976            if (rejected) {
977                untrackRejection(this);
978            }
979            return rejected ? rejected(reason) : this;
980        }
981    }, function fallback() {
982        return this;
983    }, function inspect() {
984        return { state: "rejected", reason: reason };
985    });
986
987    // Note that the reason has not been handled.
988    trackRejection(rejection, reason);
989
990    return rejection;
991}
992
993/**
994 * Constructs a fulfilled promise for an immediate reference.
995 * @param value immediate reference
996 */
997Q.fulfill = fulfill;
998function fulfill(value) {
999    return Promise({
1000        "when": function () {
1001            return value;
1002        },
1003        "get": function (name) {
1004            return value[name];
1005        },
1006        "set": function (name, rhs) {
1007            value[name] = rhs;
1008        },
1009        "delete": function (name) {
1010            delete value[name];
1011        },
1012        "post": function (name, args) {
1013            // Mark Miller proposes that post with no name should apply a
1014            // promised function.
1015            if (name === null || name === void 0) {
1016                return value.apply(void 0, args);
1017            } else {
1018                return value[name].apply(value, args);
1019            }
1020        },
1021        "apply": function (thisP, args) {
1022            return value.apply(thisP, args);
1023        },
1024        "keys": function () {
1025            return object_keys(value);
1026        }
1027    }, void 0, function inspect() {
1028        return { state: "fulfilled", value: value };
1029    });
1030}
1031
1032/**
1033 * Constructs a promise for an immediate reference, passes promises through, or
1034 * coerces promises from different systems.
1035 * @param value immediate reference or promise
1036 */
1037Q.resolve = resolve;
1038function resolve(value) {
1039    // If the object is already a Promise, return it directly.  This enables
1040    // the resolve function to both be used to created references from objects,
1041    // but to tolerably coerce non-promises to promises.
1042    if (isPromise(value)) {
1043        return value;
1044    }
1045
1046    // assimilate thenables
1047    if (isPromiseAlike(value)) {
1048        return coerce(value);
1049    } else {
1050        return fulfill(value);
1051    }
1052}
1053
1054/**
1055 * Converts thenables to Q promises.
1056 * @param promise thenable promise
1057 * @returns a Q promise
1058 */
1059function coerce(promise) {
1060    var deferred = defer();
1061    nextTick(function () {
1062        try {
1063            promise.then(deferred.resolve, deferred.reject, deferred.notify);
1064        } catch (exception) {
1065            deferred.reject(exception);
1066        }
1067    });
1068    return deferred.promise;
1069}
1070
1071/**
1072 * Annotates an object such that it will never be
1073 * transferred away from this process over any promise
1074 * communication channel.
1075 * @param object
1076 * @returns promise a wrapping of that object that
1077 * additionally responds to the "isDef" message
1078 * without a rejection.
1079 */
1080Q.master = master;
1081function master(object) {
1082    return Promise({
1083        "isDef": function () {}
1084    }, function fallback(op, args) {
1085        return dispatch(object, op, args);
1086    }, function () {
1087        return resolve(object).inspect();
1088    });
1089}
1090
1091/**
1092 * Registers an observer on a promise.
1093 *
1094 * Guarantees:
1095 *
1096 * 1. that fulfilled and rejected will be called only once.
1097 * 2. that either the fulfilled callback or the rejected callback will be
1098 *    called, but not both.
1099 * 3. that fulfilled and rejected will not be called in this turn.
1100 *
1101 * @param value      promise or immediate reference to observe
1102 * @param fulfilled  function to be called with the fulfilled value
1103 * @param rejected   function to be called with the rejection exception
1104 * @param progressed function to be called on any progress notifications
1105 * @return promise for the return value from the invoked callback
1106 */
1107Q.when = when;
1108function when(value, fulfilled, rejected, progressed) {
1109    return Q(value).then(fulfilled, rejected, progressed);
1110}
1111
1112/**
1113 * Spreads the values of a promised array of arguments into the
1114 * fulfillment callback.
1115 * @param fulfilled callback that receives variadic arguments from the
1116 * promised array
1117 * @param rejected callback that receives the exception if the promise
1118 * is rejected.
1119 * @returns a promise for the return value or thrown exception of
1120 * either callback.
1121 */
1122Q.spread = spread;
1123function spread(promise, fulfilled, rejected) {
1124    return when(promise, function (valuesOrPromises) {
1125        return all(valuesOrPromises).then(function (values) {
1126            return fulfilled.apply(void 0, values);
1127        }, rejected);
1128    }, rejected);
1129}
1130
1131/**
1132 * The async function is a decorator for generator functions, turning
1133 * them into asynchronous generators.  Although generators are only part
1134 * of the newest ECMAScript 6 drafts, this code does not cause syntax
1135 * errors in older engines.  This code should continue to work and will
1136 * in fact improve over time as the language improves.
1137 *
1138 * ES6 generators are currently part of V8 version 3.19 with the
1139 * --harmony-generators runtime flag enabled.  SpiderMonkey has had them
1140 * for longer, but under an older Python-inspired form.  This function
1141 * works on both kinds of generators.
1142 *
1143 * Decorates a generator function such that:
1144 *  - it may yield promises
1145 *  - execution will continue when that promise is fulfilled
1146 *  - the value of the yield expression will be the fulfilled value
1147 *  - it returns a promise for the return value (when the generator
1148 *    stops iterating)
1149 *  - the decorated function returns a promise for the return value
1150 *    of the generator or the first rejected promise among those
1151 *    yielded.
1152 *  - if an error is thrown in the generator, it propagates through
1153 *    every following yield until it is caught, or until it escapes
1154 *    the generator function altogether, and is translated into a
1155 *    rejection for the promise returned by the decorated generator.
1156 */
1157Q.async = async;
1158function async(makeGenerator) {
1159    return function () {
1160        // when verb is "send", arg is a value
1161        // when verb is "throw", arg is an exception
1162        function continuer(verb, arg) {
1163            var result;
1164            if (hasES6Generators) {
1165                try {
1166                    result = generator[verb](arg);
1167                } catch (exception) {
1168                    return reject(exception);
1169                }
1170                if (result.done) {
1171                    return result.value;
1172                } else {
1173                    return when(result.value, callback, errback);
1174                }
1175            } else {
1176                // FIXME: Remove this case when SM does ES6 generators.
1177                try {
1178                    result = generator[verb](arg);
1179                } catch (exception) {
1180                    if (isStopIteration(exception)) {
1181                        return exception.value;
1182                    } else {
1183                        return reject(exception);
1184                    }
1185                }
1186                return when(result, callback, errback);
1187            }
1188        }
1189        var generator = makeGenerator.apply(this, arguments);
1190        var callback = continuer.bind(continuer, "send");
1191        var errback = continuer.bind(continuer, "throw");
1192        return callback();
1193    };
1194}
1195
1196/**
1197 * The spawn function is a small wrapper around async that immediately
1198 * calls the generator and also ends the promise chain, so that any
1199 * unhandled errors are thrown instead of forwarded to the error
1200 * handler. This is useful because it's extremely common to run
1201 * generators at the top-level to work with libraries.
1202 */
1203Q.spawn = spawn;
1204function spawn(makeGenerator) {
1205    Q.done(Q.async(makeGenerator)());
1206}
1207
1208// FIXME: Remove this interface once ES6 generators are in SpiderMonkey.
1209/**
1210 * Throws a ReturnValue exception to stop an asynchronous generator.
1211 *
1212 * This interface is a stop-gap measure to support generator return
1213 * values in older Firefox/SpiderMonkey.  In browsers that support ES6
1214 * generators like Chromium 29, just use "return" in your generator
1215 * functions.
1216 *
1217 * @param value the return value for the surrounding generator
1218 * @throws ReturnValue exception with the value.
1219 * @example
1220 * // ES6 style
1221 * Q.async(function* () {
1222 *      var foo = yield getFooPromise();
1223 *      var bar = yield getBarPromise();
1224 *      return foo + bar;
1225 * })
1226 * // Older SpiderMonkey style
1227 * Q.async(function () {
1228 *      var foo = yield getFooPromise();
1229 *      var bar = yield getBarPromise();
1230 *      Q.return(foo + bar);
1231 * })
1232 */
1233Q["return"] = _return;
1234function _return(value) {
1235    throw new QReturnValue(value);
1236}
1237
1238/**
1239 * The promised function decorator ensures that any promise arguments
1240 * are settled and passed as values (`this` is also settled and passed
1241 * as a value).  It will also ensure that the result of a function is
1242 * always a promise.
1243 *
1244 * @example
1245 * var add = Q.promised(function (a, b) {
1246 *     return a + b;
1247 * });
1248 * add(Q.resolve(a), Q.resolve(B));
1249 *
1250 * @param {function} callback The function to decorate
1251 * @returns {function} a function that has been decorated.
1252 */
1253Q.promised = promised;
1254function promised(callback) {
1255    return function () {
1256        return spread([this, all(arguments)], function (self, args) {
1257            return callback.apply(self, args);
1258        });
1259    };
1260}
1261
1262/**
1263 * sends a message to a value in a future turn
1264 * @param object* the recipient
1265 * @param op the name of the message operation, e.g., "when",
1266 * @param args further arguments to be forwarded to the operation
1267 * @returns result {Promise} a promise for the result of the operation
1268 */
1269Q.dispatch = dispatch;
1270function dispatch(object, op, args) {
1271    var deferred = defer();
1272    nextTick(function () {
1273        resolve(object).promiseDispatch(deferred.resolve, op, args);
1274    });
1275    return deferred.promise;
1276}
1277
1278/**
1279 * Constructs a promise method that can be used to safely observe resolution of
1280 * a promise for an arbitrarily named method like "propfind" in a future turn.
1281 *
1282 * "dispatcher" constructs methods like "get(promise, name)" and "set(promise)".
1283 */
1284Q.dispatcher = dispatcher;
1285function dispatcher(op) {
1286    return function (object) {
1287        var args = array_slice(arguments, 1);
1288        return dispatch(object, op, args);
1289    };
1290}
1291
1292/**
1293 * Gets the value of a property in a future turn.
1294 * @param object    promise or immediate reference for target object
1295 * @param name      name of property to get
1296 * @return promise for the property value
1297 */
1298Q.get = dispatcher("get");
1299
1300/**
1301 * Sets the value of a property in a future turn.
1302 * @param object    promise or immediate reference for object object
1303 * @param name      name of property to set
1304 * @param value     new value of property
1305 * @return promise for the return value
1306 */
1307Q.set = dispatcher("set");
1308
1309/**
1310 * Deletes a property in a future turn.
1311 * @param object    promise or immediate reference for target object
1312 * @param name      name of property to delete
1313 * @return promise for the return value
1314 */
1315Q["delete"] = // XXX experimental
1316Q.del = dispatcher("delete");
1317
1318/**
1319 * Invokes a method in a future turn.
1320 * @param object    promise or immediate reference for target object
1321 * @param name      name of method to invoke
1322 * @param value     a value to post, typically an array of
1323 *                  invocation arguments for promises that
1324 *                  are ultimately backed with `resolve` values,
1325 *                  as opposed to those backed with URLs
1326 *                  wherein the posted value can be any
1327 *                  JSON serializable object.
1328 * @return promise for the return value
1329 */
1330// bound locally because it is used by other methods
1331var post = Q.post = dispatcher("post");
1332Q.mapply = post; // experimental
1333
1334/**
1335 * Invokes a method in a future turn.
1336 * @param object    promise or immediate reference for target object
1337 * @param name      name of method to invoke
1338 * @param ...args   array of invocation arguments
1339 * @return promise for the return value
1340 */
1341Q.send = send;
1342Q.invoke = send; // synonyms
1343Q.mcall = send; // experimental
1344function send(value, name) {
1345    var args = array_slice(arguments, 2);
1346    return post(value, name, args);
1347}
1348
1349/**
1350 * Applies the promised function in a future turn.
1351 * @param object    promise or immediate reference for target function
1352 * @param args      array of application arguments
1353 */
1354Q.fapply = fapply;
1355function fapply(value, args) {
1356    return dispatch(value, "apply", [void 0, args]);
1357}
1358
1359/**
1360 * Calls the promised function in a future turn.
1361 * @param object    promise or immediate reference for target function
1362 * @param ...args   array of application arguments
1363 */
1364Q["try"] = fcall; // XXX experimental
1365Q.fcall = fcall;
1366function fcall(value) {
1367    var args = array_slice(arguments, 1);
1368    return fapply(value, args);
1369}
1370
1371/**
1372 * Binds the promised function, transforming return values into a fulfilled
1373 * promise and thrown errors into a rejected one.
1374 * @param object    promise or immediate reference for target function
1375 * @param ...args   array of application arguments
1376 */
1377Q.fbind = fbind;
1378function fbind(value) {
1379    var args = array_slice(arguments, 1);
1380    return function fbound() {
1381        var allArgs = args.concat(array_slice(arguments));
1382        return dispatch(value, "apply", [this, allArgs]);
1383    };
1384}
1385
1386/**
1387 * Requests the names of the owned properties of a promised
1388 * object in a future turn.
1389 * @param object    promise or immediate reference for target object
1390 * @return promise for the keys of the eventually settled object
1391 */
1392Q.keys = dispatcher("keys");
1393
1394/**
1395 * Turns an array of promises into a promise for an array.  If any of
1396 * the promises gets rejected, the whole array is rejected immediately.
1397 * @param {Array*} an array (or promise for an array) of values (or
1398 * promises for values)
1399 * @returns a promise for an array of the corresponding values
1400 */
1401// By Mark Miller
1402// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
1403Q.all = all;
1404function all(promises) {
1405    return when(promises, function (promises) {
1406        var countDown = 0;
1407        var deferred = defer();
1408        array_reduce(promises, function (undefined, promise, index) {
1409            var snapshot;
1410            if (
1411                isPromise(promise) &&
1412                (snapshot = promise.inspect()).state === "fulfilled"
1413            ) {
1414                promises[index] = snapshot.value;
1415            } else {
1416                ++countDown;
1417                when(promise, function (value) {
1418                    promises[index] = value;
1419                    if (--countDown === 0) {
1420                        deferred.resolve(promises);
1421                    }
1422                }, deferred.reject);
1423            }
1424        }, void 0);
1425        if (countDown === 0) {
1426            deferred.resolve(promises);
1427        }
1428        return deferred.promise;
1429    });
1430}
1431
1432/**
1433 * Waits for all promises to be settled, either fulfilled or
1434 * rejected.  This is distinct from `all` since that would stop
1435 * waiting at the first rejection.  The promise returned by
1436 * `allResolved` will never be rejected.
1437 * @param promises a promise for an array (or an array) of promises
1438 * (or values)
1439 * @return a promise for an array of promises
1440 */
1441Q.allResolved = deprecate(allResolved, "allResolved", "allSettled");
1442function allResolved(promises) {
1443    return when(promises, function (promises) {
1444        promises = array_map(promises, resolve);
1445        return when(all(array_map(promises, function (promise) {
1446            return when(promise, noop, noop);
1447        })), function () {
1448            return promises;
1449        });
1450    });
1451}
1452
1453Q.allSettled = allSettled;
1454function allSettled(values) {
1455    return when(values, function (values) {
1456        return all(array_map(values, function (value, i) {
1457            return when(
1458                value,
1459                function (fulfillmentValue) {
1460                    values[i] = { state: "fulfilled", value: fulfillmentValue };
1461                    return values[i];
1462                },
1463                function (reason) {
1464                    values[i] = { state: "rejected", reason: reason };
1465                    return values[i];
1466                }
1467            );
1468        })).thenResolve(values);
1469    });
1470}
1471
1472/**
1473 * Captures the failure of a promise, giving an oportunity to recover
1474 * with a callback.  If the given promise is fulfilled, the returned
1475 * promise is fulfilled.
1476 * @param {Any*} promise for something
1477 * @param {Function} callback to fulfill the returned promise if the
1478 * given promise is rejected
1479 * @returns a promise for the return value of the callback
1480 */
1481Q["catch"] = // XXX experimental
1482Q.fail = fail;
1483function fail(promise, rejected) {
1484    return when(promise, void 0, rejected);
1485}
1486
1487/**
1488 * Attaches a listener that can respond to progress notifications from a
1489 * promise's originating deferred. This listener receives the exact arguments
1490 * passed to ``deferred.notify``.
1491 * @param {Any*} promise for something
1492 * @param {Function} callback to receive any progress notifications
1493 * @returns the given promise, unchanged
1494 */
1495Q.progress = progress;
1496function progress(promise, progressed) {
1497    return when(promise, void 0, void 0, progressed);
1498}
1499
1500/**
1501 * Provides an opportunity to observe the settling of a promise,
1502 * regardless of whether the promise is fulfilled or rejected.  Forwards
1503 * the resolution to the returned promise when the callback is done.
1504 * The callback can return a promise to defer completion.
1505 * @param {Any*} promise
1506 * @param {Function} callback to observe the resolution of the given
1507 * promise, takes no arguments.
1508 * @returns a promise for the resolution of the given promise when
1509 * ``fin`` is done.
1510 */
1511Q["finally"] = // XXX experimental
1512Q.fin = fin;
1513function fin(promise, callback) {
1514    return when(promise, function (value) {
1515        return when(callback(), function () {
1516            return value;
1517        });
1518    }, function (exception) {
1519        return when(callback(), function () {
1520            return reject(exception);
1521        });
1522    });
1523}
1524
1525/**
1526 * Terminates a chain of promises, forcing rejections to be
1527 * thrown as exceptions.
1528 * @param {Any*} promise at the end of a chain of promises
1529 * @returns nothing
1530 */
1531Q.done = done;
1532function done(promise, fulfilled, rejected, progress) {
1533    var onUnhandledError = function (error) {
1534        // forward to a future turn so that ``when``
1535        // does not catch it and turn it into a rejection.
1536        nextTick(function () {
1537            makeStackTraceLong(error, promise);
1538
1539            if (Q.onerror) {
1540                Q.onerror(error);
1541            } else {
1542                throw error;
1543            }
1544        });
1545    };
1546
1547    // Avoid unnecessary `nextTick`ing via an unnecessary `when`.
1548    var promiseToHandle = fulfilled || rejected || progress ?
1549        when(promise, fulfilled, rejected, progress) :
1550        promise;
1551
1552    if (typeof process === "object" && process && process.domain) {
1553        onUnhandledError = process.domain.bind(onUnhandledError);
1554    }
1555    fail(promiseToHandle, onUnhandledError);
1556}
1557
1558/**
1559 * Causes a promise to be rejected if it does not get fulfilled before
1560 * some milliseconds time out.
1561 * @param {Any*} promise
1562 * @param {Number} milliseconds timeout
1563 * @param {String} custom error message (optional)
1564 * @returns a promise for the resolution of the given promise if it is
1565 * fulfilled before the timeout, otherwise rejected.
1566 */
1567Q.timeout = timeout;
1568function timeout(promise, ms, msg) {
1569    var deferred = defer();
1570    var timeoutId = setTimeout(function () {
1571        deferred.reject(new Error(msg || "Timed out after " + ms + " ms"));
1572    }, ms);
1573
1574    when(promise, function (value) {
1575        clearTimeout(timeoutId);
1576        deferred.resolve(value);
1577    }, function (exception) {
1578        clearTimeout(timeoutId);
1579        deferred.reject(exception);
1580    }, deferred.notify);
1581
1582    return deferred.promise;
1583}
1584
1585/**
1586 * Returns a promise for the given value (or promised value) after some
1587 * milliseconds.
1588 * @param {Any*} promise
1589 * @param {Number} milliseconds
1590 * @returns a promise for the resolution of the given promise after some
1591 * time has elapsed.
1592 */
1593Q.delay = delay;
1594function delay(promise, timeout) {
1595    if (timeout === void 0) {
1596        timeout = promise;
1597        promise = void 0;
1598    }
1599
1600    var deferred = defer();
1601
1602    when(promise, undefined, undefined, deferred.notify);
1603    setTimeout(function () {
1604        deferred.resolve(promise);
1605    }, timeout);
1606
1607    return deferred.promise;
1608}
1609
1610/**
1611 * Passes a continuation to a Node function, which is called with the given
1612 * arguments provided as an array, and returns a promise.
1613 *
1614 *      Q.nfapply(FS.readFile, [__filename])
1615 *      .then(function (content) {
1616 *      })
1617 *
1618 */
1619Q.nfapply = nfapply;
1620function nfapply(callback, args) {
1621    var nodeArgs = array_slice(args);
1622    var deferred = defer();
1623    nodeArgs.push(deferred.makeNodeResolver());
1624
1625    fapply(callback, nodeArgs).fail(deferred.reject);
1626    return deferred.promise;
1627}
1628
1629/**
1630 * Passes a continuation to a Node function, which is called with the given
1631 * arguments provided individually, and returns a promise.
1632 *
1633 *      Q.nfcall(FS.readFile, __filename)
1634 *      .then(function (content) {
1635 *      })
1636 *
1637 */
1638Q.nfcall = nfcall;
1639function nfcall(callback/*, ...args */) {
1640    var nodeArgs = array_slice(arguments, 1);
1641    var deferred = defer();
1642    nodeArgs.push(deferred.makeNodeResolver());
1643
1644    fapply(callback, nodeArgs).fail(deferred.reject);
1645    return deferred.promise;
1646}
1647
1648/**
1649 * Wraps a NodeJS continuation passing function and returns an equivalent
1650 * version that returns a promise.
1651 *
1652 *      Q.nfbind(FS.readFile, __filename)("utf-8")
1653 *      .then(console.log)
1654 *      .done()
1655 *
1656 */
1657Q.nfbind = nfbind;
1658Q.denodeify = Q.nfbind; // synonyms
1659function nfbind(callback/*, ...args */) {
1660    var baseArgs = array_slice(arguments, 1);
1661    return function () {
1662        var nodeArgs = baseArgs.concat(array_slice(arguments));
1663        var deferred = defer();
1664        nodeArgs.push(deferred.makeNodeResolver());
1665
1666        fapply(callback, nodeArgs).fail(deferred.reject);
1667        return deferred.promise;
1668    };
1669}
1670
1671Q.nbind = nbind;
1672function nbind(callback, thisArg /*, ... args*/) {
1673    var baseArgs = array_slice(arguments, 2);
1674    return function () {
1675        var nodeArgs = baseArgs.concat(array_slice(arguments));
1676        var deferred = defer();
1677        nodeArgs.push(deferred.makeNodeResolver());
1678
1679        function bound() {
1680            return callback.apply(thisArg, arguments);
1681        }
1682
1683        fapply(bound, nodeArgs).fail(deferred.reject);
1684        return deferred.promise;
1685    };
1686}
1687
1688/**
1689 * Calls a method of a Node-style object that accepts a Node-style
1690 * callback with a given array of arguments, plus a provided callback.
1691 * @param object an object that has the named method
1692 * @param {String} name name of the method of object
1693 * @param {Array} args arguments to pass to the method; the callback
1694 * will be provided by Q and appended to these arguments.
1695 * @returns a promise for the value or error
1696 */
1697Q.npost = npost;
1698Q.nmapply = npost; // synonyms
1699function npost(object, name, args) {
1700    var nodeArgs = array_slice(args || []);
1701    var deferred = defer();
1702    nodeArgs.push(deferred.makeNodeResolver());
1703
1704    post(object, name, nodeArgs).fail(deferred.reject);
1705    return deferred.promise;
1706}
1707
1708/**
1709 * Calls a method of a Node-style object that accepts a Node-style
1710 * callback, forwarding the given variadic arguments, plus a provided
1711 * callback argument.
1712 * @param object an object that has the named method
1713 * @param {String} name name of the method of object
1714 * @param ...args arguments to pass to the method; the callback will
1715 * be provided by Q and appended to these arguments.
1716 * @returns a promise for the value or error
1717 */
1718Q.nsend = nsend;
1719Q.ninvoke = Q.nsend; // synonyms
1720Q.nmcall = Q.nsend; // synonyms
1721function nsend(object, name /*, ...args*/) {
1722    var nodeArgs = array_slice(arguments, 2);
1723    var deferred = defer();
1724    nodeArgs.push(deferred.makeNodeResolver());
1725    post(object, name, nodeArgs).fail(deferred.reject);
1726    return deferred.promise;
1727}
1728
1729Q.nodeify = nodeify;
1730function nodeify(promise, nodeback) {
1731    if (nodeback) {
1732        promise.then(function (value) {
1733            nextTick(function () {
1734                nodeback(null, value);
1735            });
1736        }, function (error) {
1737            nextTick(function () {
1738                nodeback(error);
1739            });
1740        });
1741    } else {
1742        return promise;
1743    }
1744}
1745
1746// All code before this point will be filtered from stack traces.
1747var qEndingLine = captureLine();
1748
1749return Q;
1750
1751});
Note: See TracBrowser for help on using the repository browser.