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