thenable.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright 2013 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. goog.provide('goog.Thenable');
  15. /** @suppress {extraRequire} */
  16. goog.forwardDeclare('goog.Promise'); // for the type reference.
  17. /**
  18. * Provides a more strict interface for Thenables in terms of
  19. * http://promisesaplus.com for interop with {@see goog.Promise}.
  20. *
  21. * @interface
  22. * @extends {IThenable<TYPE>}
  23. * @template TYPE
  24. */
  25. goog.Thenable = function() {};
  26. /**
  27. * Adds callbacks that will operate on the result of the Thenable, returning a
  28. * new child Promise.
  29. *
  30. * If the Thenable is fulfilled, the {@code onFulfilled} callback will be
  31. * invoked with the fulfillment value as argument, and the child Promise will
  32. * be fulfilled with the return value of the callback. If the callback throws
  33. * an exception, the child Promise will be rejected with the thrown value
  34. * instead.
  35. *
  36. * If the Thenable is rejected, the {@code onRejected} callback will be invoked
  37. * with the rejection reason as argument, and the child Promise will be rejected
  38. * with the return value of the callback or thrown value.
  39. *
  40. * @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A
  41. * function that will be invoked with the fulfillment value if the Promise
  42. * is fulfilled.
  43. * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will
  44. * be invoked with the rejection reason if the Promise is rejected.
  45. * @param {THIS=} opt_context An optional context object that will be the
  46. * execution context for the callbacks. By default, functions are executed
  47. * with the default this.
  48. *
  49. * @return {RESULT} A new Promise that will receive the result
  50. * of the fulfillment or rejection callback.
  51. * @template VALUE
  52. * @template THIS
  53. *
  54. * When a Promise (or thenable) is returned from the fulfilled callback,
  55. * the result is the payload of that promise, not the promise itself.
  56. *
  57. * @template RESULT := type('goog.Promise',
  58. * cond(isUnknown(VALUE), unknown(),
  59. * mapunion(VALUE, (V) =>
  60. * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),
  61. * templateTypeOf(V, 0),
  62. * cond(sub(V, 'Thenable'),
  63. * unknown(),
  64. * V)))))
  65. * =:
  66. *
  67. */
  68. goog.Thenable.prototype.then = function(
  69. opt_onFulfilled, opt_onRejected, opt_context) {};
  70. /**
  71. * An expando property to indicate that an object implements
  72. * {@code goog.Thenable}.
  73. *
  74. * {@see addImplementation}.
  75. *
  76. * @const
  77. */
  78. goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable';
  79. /**
  80. * Marks a given class (constructor) as an implementation of Thenable, so
  81. * that we can query that fact at runtime. The class must have already
  82. * implemented the interface.
  83. * Exports a 'then' method on the constructor prototype, so that the objects
  84. * also implement the extern {@see goog.Thenable} interface for interop with
  85. * other Promise implementations.
  86. * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The
  87. * corresponding class must have already implemented the interface.
  88. */
  89. goog.Thenable.addImplementation = function(ctor) {
  90. // Use bracket notation instead of goog.exportSymbol() so that the compiler
  91. // won't create a 'var ctor;' extern when the "create externs from exports"
  92. // mode is enabled.
  93. ctor.prototype['then'] = ctor.prototype.then;
  94. if (COMPILED) {
  95. ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true;
  96. } else {
  97. // Avoids dictionary access in uncompiled mode.
  98. ctor.prototype.$goog_Thenable = true;
  99. }
  100. };
  101. /**
  102. * @param {?} object
  103. * @return {boolean} Whether a given instance implements {@code goog.Thenable}.
  104. * The class/superclass of the instance must call {@code addImplementation}.
  105. */
  106. goog.Thenable.isImplementedBy = function(object) {
  107. if (!object) {
  108. return false;
  109. }
  110. try {
  111. if (COMPILED) {
  112. return !!object[goog.Thenable.IMPLEMENTED_BY_PROP];
  113. }
  114. return !!object.$goog_Thenable;
  115. } catch (e) {
  116. // Property access seems to be forbidden.
  117. return false;
  118. }
  119. };