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