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