You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

874 lines
25 KiB

4 years ago
  1. [![Build Status](https://secure.travis-ci.org/kriskowal/q.svg?branch=master)](http://travis-ci.org/kriskowal/q)
  2. [![CDNJS](https://img.shields.io/cdnjs/v/q.js.svg)](https://cdnjs.com/libraries/q.js)
  3. <a href="http://promises-aplus.github.com/promises-spec">
  4. <img src="http://kriskowal.github.io/q/q.png" align="right" alt="Q logo" />
  5. </a>
  6. If a function cannot return a value or throw an exception without
  7. blocking, it can return a promise instead. A promise is an object
  8. that represents the return value or the thrown exception that the
  9. function may eventually provide. A promise can also be used as a
  10. proxy for a [remote object][Q-Connection] to overcome latency.
  11. [Q-Connection]: https://github.com/kriskowal/q-connection
  12. On the first pass, promises can mitigate the “[Pyramid of
  13. Doom][POD]”: the situation where code marches to the right faster
  14. than it marches forward.
  15. [POD]: http://calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web/
  16. ```javascript
  17. step1(function (value1) {
  18. step2(value1, function(value2) {
  19. step3(value2, function(value3) {
  20. step4(value3, function(value4) {
  21. // Do something with value4
  22. });
  23. });
  24. });
  25. });
  26. ```
  27. With a promise library, you can flatten the pyramid.
  28. ```javascript
  29. Q.fcall(promisedStep1)
  30. .then(promisedStep2)
  31. .then(promisedStep3)
  32. .then(promisedStep4)
  33. .then(function (value4) {
  34. // Do something with value4
  35. })
  36. .catch(function (error) {
  37. // Handle any error from all above steps
  38. })
  39. .done();
  40. ```
  41. With this approach, you also get implicit error propagation, just like `try`,
  42. `catch`, and `finally`. An error in `promisedStep1` will flow all the way to
  43. the `catch` function, where it’s caught and handled. (Here `promisedStepN` is
  44. a version of `stepN` that returns a promise.)
  45. The callback approach is called an “inversion of control”.
  46. A function that accepts a callback instead of a return value
  47. is saying, “Don’t call me, I’ll call you.”. Promises
  48. [un-invert][IOC] the inversion, cleanly separating the input
  49. arguments from control flow arguments. This simplifies the
  50. use and creation of API’s, particularly variadic,
  51. rest and spread arguments.
  52. [IOC]: http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript
  53. ## Getting Started
  54. The Q module can be loaded as:
  55. - A ``<script>`` tag (creating a ``Q`` global variable): ~2.5 KB minified and
  56. gzipped.
  57. - A Node.js and CommonJS module, available in [npm](https://npmjs.org/) as
  58. the [q](https://npmjs.org/package/q) package
  59. - An AMD module
  60. - A [component](https://github.com/component/component) as ``microjs/q``
  61. - Using [bower](http://bower.io/) as `q#^1.4.1`
  62. - Using [NuGet](http://nuget.org/) as [Q](https://nuget.org/packages/q)
  63. Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.
  64. ## Resources
  65. Our [wiki][] contains a number of useful resources, including:
  66. - A method-by-method [Q API reference][reference].
  67. - A growing [examples gallery][examples], showing how Q can be used to make
  68. everything better. From XHR to database access to accessing the Flickr API,
  69. Q is there for you.
  70. - There are many libraries that produce and consume Q promises for everything
  71. from file system/database access or RPC to templating. For a list of some of
  72. the more popular ones, see [Libraries][].
  73. - If you want materials that introduce the promise concept generally, and the
  74. below tutorial isn't doing it for you, check out our collection of
  75. [presentations, blog posts, and podcasts][resources].
  76. - A guide for those [coming from jQuery's `$.Deferred`][jquery].
  77. We'd also love to have you join the Q-Continuum [mailing list][].
  78. [wiki]: https://github.com/kriskowal/q/wiki
  79. [reference]: https://github.com/kriskowal/q/wiki/API-Reference
  80. [examples]: https://github.com/kriskowal/q/wiki/Examples-Gallery
  81. [Libraries]: https://github.com/kriskowal/q/wiki/Libraries
  82. [resources]: https://github.com/kriskowal/q/wiki/General-Promise-Resources
  83. [jquery]: https://github.com/kriskowal/q/wiki/Coming-from-jQuery
  84. [mailing list]: https://groups.google.com/forum/#!forum/q-continuum
  85. ## Tutorial
  86. Promises have a ``then`` method, which you can use to get the eventual
  87. return value (fulfillment) or thrown exception (rejection).
  88. ```javascript
  89. promiseMeSomething()
  90. .then(function (value) {
  91. }, function (reason) {
  92. });
  93. ```
  94. If ``promiseMeSomething`` returns a promise that gets fulfilled later
  95. with a return value, the first function (the fulfillment handler) will be
  96. called with the value. However, if the ``promiseMeSomething`` function
  97. gets rejected later by a thrown exception, the second function (the
  98. rejection handler) will be called with the exception.
  99. Note that resolution of a promise is always asynchronous: that is, the
  100. fulfillment or rejection handler will always be called in the next turn of the
  101. event loop (i.e. `process.nextTick` in Node). This gives you a nice
  102. guarantee when mentally tracing the flow of your code, namely that
  103. ``then`` will always return before either handler is executed.
  104. In this tutorial, we begin with how to consume and work with promises. We'll
  105. talk about how to create them, and thus create functions like
  106. `promiseMeSomething` that return promises, [below](#the-beginning).
  107. ### Propagation
  108. The ``then`` method returns a promise, which in this example, I’m
  109. assigning to ``outputPromise``.
  110. ```javascript
  111. var outputPromise = getInputPromise()
  112. .then(function (input) {
  113. }, function (reason) {
  114. });
  115. ```
  116. The ``outputPromise`` variable becomes a new promise for the return
  117. value of either handler. Since a function can only either return a
  118. value or throw an exception, only one handler will ever be called and it
  119. will be responsible for resolving ``outputPromise``.
  120. - If you return a value in a handler, ``outputPromise`` will get
  121. fulfilled.
  122. - If you throw an exception in a handler, ``outputPromise`` will get
  123. rejected.
  124. - If you return a **promise** in a handler, ``outputPromise`` will
  125. “become” that promise. Being able to become a new promise is useful
  126. for managing delays, combining results, or recovering from errors.
  127. If the ``getInputPromise()`` promise gets rejected and you omit the
  128. rejection handler, the **error** will go to ``outputPromise``:
  129. ```javascript
  130. var outputPromise = getInputPromise()
  131. .then(function (value) {
  132. });
  133. ```
  134. If the input promise gets fulfilled and you omit the fulfillment handler, the
  135. **value** will go to ``outputPromise``:
  136. ```javascript
  137. var outputPromise = getInputPromise()
  138. .then(null, function (error) {
  139. });
  140. ```
  141. Q promises provide a ``fail`` shorthand for ``then`` when you are only
  142. interested in handling the error:
  143. ```javascript
  144. var outputPromise = getInputPromise()
  145. .fail(function (error) {
  146. });
  147. ```
  148. If you are writing JavaScript for modern engines only or using
  149. CoffeeScript, you may use `catch` instead of `fail`.
  150. Promises also have a ``fin`` function that is like a ``finally`` clause.
  151. The final handler gets called, with no arguments, when the promise
  152. returned by ``getInputPromise()`` either returns a value or throws an
  153. error. The value returned or error thrown by ``getInputPromise()``
  154. passes directly to ``outputPromise`` unless the final handler fails, and
  155. may be delayed if the final handler returns a promise.
  156. ```javascript
  157. var outputPromise = getInputPromise()
  158. .fin(function () {
  159. // close files, database connections, stop servers, conclude tests
  160. });
  161. ```
  162. - If the handler returns a value, the value is ignored
  163. - If the handler throws an error, the error passes to ``outputPromise``
  164. - If the handler returns a promise, ``outputPromise`` gets postponed. The
  165. eventual value or error has the same effect as an immediate return
  166. value or thrown error: a value would be ignored, an error would be
  167. forwarded.
  168. If you are writing JavaScript for modern engines only or using
  169. CoffeeScript, you may use `finally` instead of `fin`.
  170. ### Chaining
  171. There are two ways to chain promises. You can chain promises either
  172. inside or outside handlers. The next two examples are equivalent.
  173. ```javascript
  174. return getUsername()
  175. .then(function (username) {
  176. return getUser(username)
  177. .then(function (user) {
  178. // if we get here without an error,
  179. // the value returned here
  180. // or the exception thrown here
  181. // resolves the promise returned
  182. // by the first line
  183. })
  184. });
  185. ```
  186. ```javascript
  187. return getUsername()
  188. .then(function (username) {
  189. return getUser(username);
  190. })
  191. .then(function (user) {
  192. // if we get here without an error,
  193. // the value returned here
  194. // or the exception thrown here
  195. // resolves the promise returned
  196. // by the first line
  197. });
  198. ```
  199. The only difference is nesting. It’s useful to nest handlers if you
  200. need to capture multiple input values in your closure.
  201. ```javascript
  202. function authenticate() {
  203. return getUsername()
  204. .then(function (username) {
  205. return getUser(username);
  206. })
  207. // chained because we will not need the user name in the next event
  208. .then(function (user) {
  209. return getPassword()
  210. // nested because we need both user and password next
  211. .then(function (password) {
  212. if (user.passwordHash !== hash(password)) {
  213. throw new Error("Can't authenticate");
  214. }
  215. });
  216. });
  217. }
  218. ```
  219. ### Combination
  220. You can turn an array of promises into a promise for the whole,
  221. fulfilled array using ``all``.
  222. ```javascript
  223. return Q.all([
  224. eventualAdd(2, 2),
  225. eventualAdd(10, 20)
  226. ]);
  227. ```
  228. If you have a promise for an array, you can use ``spread`` as a
  229. replacement for ``then``. The ``spread`` function “spreads” the
  230. values over the arguments of the fulfillment handler. The rejection handler
  231. will get called at the first sign of failure. That is, whichever of
  232. the received promises fails first gets handled by the rejection handler.
  233. ```javascript
  234. function eventualAdd(a, b) {
  235. return Q.spread([a, b], function (a, b) {
  236. return a + b;
  237. })
  238. }
  239. ```
  240. But ``spread`` calls ``all`` initially, so you can skip it in chains.
  241. ```javascript
  242. return getUsername()
  243. .then(function (username) {
  244. return [username, getUser(username)];
  245. })
  246. .spread(function (username, user) {
  247. });
  248. ```
  249. The ``all`` function returns a promise for an array of values. When this
  250. promise is fulfilled, the array contains the fulfillment values of the original
  251. promises, in the same order as those promises. If one of the given promises
  252. is rejected, the returned promise is immediately rejected, not waiting for the
  253. rest of the batch. If you want to wait for all of the promises to either be
  254. fulfilled or rejected, you can use ``allSettled``.
  255. ```javascript
  256. Q.allSettled(promises)
  257. .then(function (results) {
  258. results.forEach(function (result) {
  259. if (result.state === "fulfilled") {
  260. var value = result.value;
  261. } else {
  262. var reason = result.reason;
  263. }
  264. });
  265. });
  266. ```
  267. The ``any`` function accepts an array of promises and returns a promise that is
  268. fulfilled by the first given promise to be fulfilled, or rejected if all of the
  269. given promises are rejected.
  270. ```javascript
  271. Q.any(promises)
  272. .then(function (first) {
  273. // Any of the promises was fulfilled.
  274. }, function (error) {
  275. // All of the promises were rejected.
  276. });
  277. ```
  278. ### Sequences
  279. If you have a number of promise-producing functions that need
  280. to be run sequentially, you can of course do so manually:
  281. ```javascript
  282. return foo(initialVal).then(bar).then(baz).then(qux);
  283. ```
  284. However, if you want to run a dynamically constructed sequence of
  285. functions, you'll want something like this:
  286. ```javascript
  287. var funcs = [foo, bar, baz, qux];
  288. var result = Q(initialVal);
  289. funcs.forEach(function (f) {
  290. result = result.then(f);
  291. });
  292. return result;
  293. ```
  294. You can make this slightly more compact using `reduce`:
  295. ```javascript
  296. return funcs.reduce(function (soFar, f) {
  297. return soFar.then(f);
  298. }, Q(initialVal));
  299. ```
  300. Or, you could use the ultra-compact version:
  301. ```javascript
  302. return funcs.reduce(Q.when, Q(initialVal));
  303. ```
  304. ### Handling Errors
  305. One sometimes-unintuitive aspect of promises is that if you throw an
  306. exception in the fulfillment handler, it will not be caught by the error
  307. handler.
  308. ```javascript
  309. return foo()
  310. .then(function (value) {
  311. throw new Error("Can't bar.");
  312. }, function (error) {
  313. // We only get here if "foo" fails
  314. });
  315. ```
  316. To see why this is, consider the parallel between promises and
  317. ``try``/``catch``. We are ``try``-ing to execute ``foo()``: the error
  318. handler represents a ``catch`` for ``foo()``, while the fulfillment handler
  319. represents code that happens *after* the ``try``/``catch`` block.
  320. That code then needs its own ``try``/``catch`` block.
  321. In terms of promises, this means chaining your rejection handler:
  322. ```javascript
  323. return foo()
  324. .then(function (value) {
  325. throw new Error("Can't bar.");
  326. })
  327. .fail(function (error) {
  328. // We get here with either foo's error or bar's error
  329. });
  330. ```
  331. ### Progress Notification
  332. It's possible for promises to report their progress, e.g. for tasks that take a
  333. long time like a file upload. Not all promises will implement progress
  334. notifications, but for those that do, you can consume the progress values using
  335. a third parameter to ``then``:
  336. ```javascript
  337. return uploadFile()
  338. .then(function () {
  339. // Success uploading the file
  340. }, function (err) {
  341. // There was an error, and we get the reason for error
  342. }, function (progress) {
  343. // We get notified of the upload's progress as it is executed
  344. });
  345. ```
  346. Like `fail`, Q also provides a shorthand for progress callbacks
  347. called `progress`:
  348. ```javascript
  349. return uploadFile().progress(function (progress) {
  350. // We get notified of the upload's progress
  351. });
  352. ```
  353. ### The End
  354. When you get to the end of a chain of promises, you should either
  355. return the last promise or end the chain. Since handlers catch
  356. errors, it’s an unfortunate pattern that the exceptions can go
  357. unobserved.
  358. So, either return it,
  359. ```javascript
  360. return foo()
  361. .then(function () {
  362. return "bar";
  363. });
  364. ```
  365. Or, end it.
  366. ```javascript
  367. foo()
  368. .then(function () {
  369. return "bar";
  370. })
  371. .done();
  372. ```
  373. Ending a promise chain makes sure that, if an error doesn’t get
  374. handled before the end, it will get rethrown and reported.
  375. This is a stopgap. We are exploring ways to make unhandled errors
  376. visible without any explicit handling.
  377. ### The Beginning
  378. Everything above assumes you get a promise from somewhere else. This
  379. is the common case. Every once in a while, you will need to create a
  380. promise from scratch.
  381. #### Using ``Q.fcall``
  382. You can create a promise from a value using ``Q.fcall``. This returns a
  383. promise for 10.
  384. ```javascript
  385. return Q.fcall(function () {
  386. return 10;
  387. });
  388. ```
  389. You can also use ``fcall`` to get a promise for an exception.
  390. ```javascript
  391. return Q.fcall(function () {
  392. throw new Error("Can't do it");
  393. });
  394. ```
  395. As the name implies, ``fcall`` can call functions, or even promised
  396. functions. This uses the ``eventualAdd`` function above to add two
  397. numbers.
  398. ```javascript
  399. return Q.fcall(eventualAdd, 2, 2);
  400. ```
  401. #### Using Deferreds
  402. If you have to interface with asynchronous functions that are callback-based
  403. instead of promise-based, Q provides a few shortcuts (like ``Q.nfcall`` and
  404. friends). But much of the time, the solution will be to use *deferreds*.
  405. ```javascript
  406. var deferred = Q.defer();
  407. FS.readFile("foo.txt", "utf-8", function (error, text) {
  408. if (error) {
  409. deferred.reject(new Error(error));
  410. } else {
  411. deferred.resolve(text);
  412. }
  413. });
  414. return deferred.promise;
  415. ```
  416. Note that a deferred can be resolved with a value or a promise. The
  417. ``reject`` function is a shorthand for resolving with a rejected
  418. promise.
  419. ```javascript
  420. // this:
  421. deferred.reject(new Error("Can't do it"));
  422. // is shorthand for:
  423. var rejection = Q.fcall(function () {
  424. throw new Error("Can't do it");
  425. });
  426. deferred.resolve(rejection);
  427. ```
  428. This is a simplified implementation of ``Q.delay``.
  429. ```javascript
  430. function delay(ms) {
  431. var deferred = Q.defer();
  432. setTimeout(deferred.resolve, ms);
  433. return deferred.promise;
  434. }
  435. ```
  436. This is a simplified implementation of ``Q.timeout``
  437. ```javascript
  438. function timeout(promise, ms) {
  439. var deferred = Q.defer();
  440. Q.when(promise, deferred.resolve);
  441. delay(ms).then(function () {
  442. deferred.reject(new Error("Timed out"));
  443. });
  444. return deferred.promise;
  445. }
  446. ```
  447. Finally, you can send a progress notification to the promise with
  448. ``deferred.notify``.
  449. For illustration, this is a wrapper for XML HTTP requests in the browser. Note
  450. that a more [thorough][XHR] implementation would be in order in practice.
  451. [XHR]: https://github.com/montagejs/mr/blob/71e8df99bb4f0584985accd6f2801ef3015b9763/browser.js#L29-L73
  452. ```javascript
  453. function requestOkText(url) {
  454. var request = new XMLHttpRequest();
  455. var deferred = Q.defer();
  456. request.open("GET", url, true);
  457. request.onload = onload;
  458. request.onerror = onerror;
  459. request.onprogress = onprogress;
  460. request.send();
  461. function onload() {
  462. if (request.status === 200) {
  463. deferred.resolve(request.responseText);
  464. } else {
  465. deferred.reject(new Error("Status code was " + request.status));
  466. }
  467. }
  468. function onerror() {
  469. deferred.reject(new Error("Can't XHR " + JSON.stringify(url)));
  470. }
  471. function onprogress(event) {
  472. deferred.notify(event.loaded / event.total);
  473. }
  474. return deferred.promise;
  475. }
  476. ```
  477. Below is an example of how to use this ``requestOkText`` function:
  478. ```javascript
  479. requestOkText("http://localhost:3000")
  480. .then(function (responseText) {
  481. // If the HTTP response returns 200 OK, log the response text.
  482. console.log(responseText);
  483. }, function (error) {
  484. // If there's an error or a non-200 status code, log the error.
  485. console.error(error);
  486. }, function (progress) {
  487. // Log the progress as it comes in.
  488. console.log("Request progress: " + Math.round(progress * 100) + "%");
  489. });
  490. ```
  491. #### Using `Q.Promise`
  492. This is an alternative promise-creation API that has the same power as
  493. the deferred concept, but without introducing another conceptual entity.
  494. Rewriting the `requestOkText` example above using `Q.Promise`:
  495. ```javascript
  496. function requestOkText(url) {
  497. return Q.Promise(function(resolve, reject, notify) {
  498. var request = new XMLHttpRequest();
  499. request.open("GET", url, true);
  500. request.onload = onload;
  501. request.onerror = onerror;
  502. request.onprogress = onprogress;
  503. request.send();
  504. function onload() {
  505. if (request.status === 200) {
  506. resolve(request.responseText);
  507. } else {
  508. reject(new Error("Status code was " + request.status));
  509. }
  510. }
  511. function onerror() {
  512. reject(new Error("Can't XHR " + JSON.stringify(url)));
  513. }
  514. function onprogress(event) {
  515. notify(event.loaded / event.total);
  516. }
  517. });
  518. }
  519. ```
  520. If `requestOkText` were to throw an exception, the returned promise would be
  521. rejected with that thrown exception as the rejection reason.
  522. ### The Middle
  523. If you are using a function that may return a promise, but just might
  524. return a value if it doesn’t need to defer, you can use the “static”
  525. methods of the Q library.
  526. The ``when`` function is the static equivalent for ``then``.
  527. ```javascript
  528. return Q.when(valueOrPromise, function (value) {
  529. }, function (error) {
  530. });
  531. ```
  532. All of the other methods on a promise have static analogs with the
  533. same name.
  534. The following are equivalent:
  535. ```javascript
  536. return Q.all([a, b]);
  537. ```
  538. ```javascript
  539. return Q.fcall(function () {
  540. return [a, b];
  541. })
  542. .all();
  543. ```
  544. When working with promises provided by other libraries, you should
  545. convert it to a Q promise. Not all promise libraries make the same
  546. guarantees as Q and certainly don’t provide all of the same methods.
  547. Most libraries only provide a partially functional ``then`` method.
  548. This thankfully is all we need to turn them into vibrant Q promises.
  549. ```javascript
  550. return Q($.ajax(...))
  551. .then(function () {
  552. });
  553. ```
  554. If there is any chance that the promise you receive is not a Q promise
  555. as provided by your library, you should wrap it using a Q function.
  556. You can even use ``Q.invoke`` as a shorthand.
  557. ```javascript
  558. return Q.invoke($, 'ajax', ...)
  559. .then(function () {
  560. });
  561. ```
  562. ### Over the Wire
  563. A promise can serve as a proxy for another object, even a remote
  564. object. There are methods that allow you to optimistically manipulate
  565. properties or call functions. All of these interactions return
  566. promises, so they can be chained.
  567. ```
  568. direct manipulation using a promise as a proxy
  569. -------------------------- -------------------------------
  570. value.foo promise.get("foo")
  571. value.foo = value promise.put("foo", value)
  572. delete value.foo promise.del("foo")
  573. value.foo(...args) promise.post("foo", [args])
  574. value.foo(...args) promise.invoke("foo", ...args)
  575. value(...args) promise.fapply([args])
  576. value(...args) promise.fcall(...args)
  577. ```
  578. If the promise is a proxy for a remote object, you can shave
  579. round-trips by using these functions instead of ``then``. To take
  580. advantage of promises for remote objects, check out [Q-Connection][].
  581. [Q-Connection]: https://github.com/kriskowal/q-connection
  582. Even in the case of non-remote objects, these methods can be used as
  583. shorthand for particularly-simple fulfillment handlers. For example, you
  584. can replace
  585. ```javascript
  586. return Q.fcall(function () {
  587. return [{ foo: "bar" }, { foo: "baz" }];
  588. })
  589. .then(function (value) {
  590. return value[0].foo;
  591. });
  592. ```
  593. with
  594. ```javascript
  595. return Q.fcall(function () {
  596. return [{ foo: "bar" }, { foo: "baz" }];
  597. })
  598. .get(0)
  599. .get("foo");
  600. ```
  601. ### Adapting Node
  602. If you're working with functions that make use of the Node.js callback pattern,
  603. where callbacks are in the form of `function(err, result)`, Q provides a few
  604. useful utility functions for converting between them. The most straightforward
  605. are probably `Q.nfcall` and `Q.nfapply` ("Node function call/apply") for calling
  606. Node.js-style functions and getting back a promise:
  607. ```javascript
  608. return Q.nfcall(FS.readFile, "foo.txt", "utf-8");
  609. return Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]);
  610. ```
  611. If you are working with methods, instead of simple functions, you can easily
  612. run in to the usual problems where passing a method to another function—like
  613. `Q.nfcall`—"un-binds" the method from its owner. To avoid this, you can either
  614. use `Function.prototype.bind` or some nice shortcut methods we provide:
  615. ```javascript
  616. return Q.ninvoke(redisClient, "get", "user:1:id");
  617. return Q.npost(redisClient, "get", ["user:1:id"]);
  618. ```
  619. You can also create reusable wrappers with `Q.denodeify` or `Q.nbind`:
  620. ```javascript
  621. var readFile = Q.denodeify(FS.readFile);
  622. return readFile("foo.txt", "utf-8");
  623. var redisClientGet = Q.nbind(redisClient.get, redisClient);
  624. return redisClientGet("user:1:id");
  625. ```
  626. Finally, if you're working with raw deferred objects, there is a
  627. `makeNodeResolver` method on deferreds that can be handy:
  628. ```javascript
  629. var deferred = Q.defer();
  630. FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
  631. return deferred.promise;
  632. ```
  633. ### Long Stack Traces
  634. Q comes with optional support for “long stack traces,” wherein the `stack`
  635. property of `Error` rejection reasons is rewritten to be traced along
  636. asynchronous jumps instead of stopping at the most recent one. As an example:
  637. ```js
  638. function theDepthsOfMyProgram() {
  639. Q.delay(100).done(function explode() {
  640. throw new Error("boo!");
  641. });
  642. }
  643. theDepthsOfMyProgram();
  644. ```
  645. usually would give a rather unhelpful stack trace looking something like
  646. ```
  647. Error: boo!
  648. at explode (/path/to/test.js:3:11)
  649. at _fulfilled (/path/to/test.js:q:54)
  650. at resolvedValue.promiseDispatch.done (/path/to/q.js:823:30)
  651. at makePromise.promise.promiseDispatch (/path/to/q.js:496:13)
  652. at pending (/path/to/q.js:397:39)
  653. at process.startup.processNextTick.process._tickCallback (node.js:244:9)
  654. ```
  655. But, if you turn this feature on by setting
  656. ```js
  657. Q.longStackSupport = true;
  658. ```
  659. then the above code gives a nice stack trace to the tune of
  660. ```
  661. Error: boo!
  662. at explode (/path/to/test.js:3:11)
  663. From previous event:
  664. at theDepthsOfMyProgram (/path/to/test.js:2:16)
  665. at Object.<anonymous> (/path/to/test.js:7:1)
  666. ```
  667. Note how you can see the function that triggered the async operation in the
  668. stack trace! This is very helpful for debugging, as otherwise you end up getting
  669. only the first line, plus a bunch of Q internals, with no sign of where the
  670. operation started.
  671. In node.js, this feature can also be enabled through the Q_DEBUG environment
  672. variable:
  673. ```
  674. Q_DEBUG=1 node server.js
  675. ```
  676. This will enable long stack support in every instance of Q.
  677. This feature does come with somewhat-serious performance and memory overhead,
  678. however. If you're working with lots of promises, or trying to scale a server
  679. to many users, you should probably keep it off. But in development, go for it!
  680. ## Tests
  681. You can view the results of the Q test suite [in your browser][tests]!
  682. [tests]: https://rawgithub.com/kriskowal/q/v1/spec/q-spec.html
  683. ## License
  684. Copyright 2009–2017 Kristopher Michael Kowal and contributors
  685. MIT License (enclosed)