promise.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // Copyright 2015 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utilities for working with promises.
  16. * Note that this file is written ES5-only.
  17. */
  18. goog.module('goog.labs.promise');
  19. var Promise = goog.require('goog.Promise');
  20. /**
  21. * Executes an ES6 generator function that may yield Promises, blocking after
  22. * each Promise until it settles. Within the generator, the value of each
  23. * 'yield' expression becomes the resolved value of the yielded promise.
  24. *
  25. * If the generator function throws an exception or yields a rejected promise,
  26. * execution stops, and the promise returned by this function is rejected.
  27. *
  28. * A typical call uses generator function syntax:
  29. *
  30. * goog.labs.promise.run(function*() {
  31. * console.log('about to start waiting');
  32. * while (needsToWait()) {
  33. * // Wait 10 seconds.
  34. * yield goog.Timer.promise(10000);
  35. * console.log('still waiting...');
  36. * }
  37. * }).then(() => {
  38. * console.log('done waiting');
  39. * });
  40. *
  41. * This function can also be used to simplify asynchronous code:
  42. *
  43. * goog.labs.promise.run(function*()) {
  44. * var x = yield somethingThatReturnsAPromise();
  45. * var y = yield somethingElseThatReturnsAPromise();
  46. * return x + y;
  47. * }).then(sum => {
  48. * console.log('The sum is:', sum);
  49. * });
  50. *
  51. * @param {function(this: CONTEXT):TYPE} generatorFunc A function which is
  52. * called immediately and returns a generator.
  53. * @param {CONTEXT=} opt_context The context in which generatorFunc should be
  54. * called.
  55. * @return {!goog.Promise<TYPE>} A promise that is resolved when the generator
  56. * returned from generatorFunc is exhausted, or rejected if an error occurs.
  57. * If the generator function returns, this promise resolves to the returned
  58. * value.
  59. * @template CONTEXT, TYPE
  60. */
  61. exports.run = function(generatorFunc, opt_context) {
  62. var generator = generatorFunc.call(opt_context);
  63. /**
  64. * @param {*} previousResolvedValue
  65. * @param {boolean=} opt_isRejected
  66. */
  67. function loop(previousResolvedValue, opt_isRejected) {
  68. var gen = opt_isRejected ? generator['throw'](previousResolvedValue) :
  69. generator.next(previousResolvedValue);
  70. if (!gen.done) {
  71. // Wrap gen.value in a promise in case it isn't a promise already.
  72. return Promise.resolve(gen.value).then(
  73. function(resolvedValue) { return loop(resolvedValue); },
  74. function(rejectValue) { return loop(rejectValue, true); });
  75. }
  76. return gen.value;
  77. }
  78. // Call loop() from then() to ensure exceptions are captured.
  79. return Promise.resolve().then(loop);
  80. };