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