# lib/goog/promise/thenable.js

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): VALUE)=} opt_onFulfilled A
45 | * function that will be invoked with the fulfillment value if the Promise
46 | * is fullfilled.
47 | * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will
48 | * be invoked with the rejection reason if the Promise is rejected.
49 | * @param {THIS=} opt_context An optional context object that will be the
50 | * execution context for the callbacks. By default, functions are executed
51 | * with the default this.
52 | *
53 | * @return {RESULT} A new Promise that will receive the result
54 | * of the fulfillment or rejection callback.
55 | * @template VALUE
56 | * @template THIS
57 | *
58 | * When a Promise (or thenable) is returned from the fulfilled callback,
59 | * the result is the payload of that promise, not the promise itself.
60 | *
61 | * @template RESULT := type('goog.Promise',
62 | * cond(isUnknown(VALUE), unknown(),
63 | * mapunion(VALUE, (V) =>
64 | * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),
65 | * templateTypeOf(V, 0),
66 | * cond(sub(V, 'Thenable'),
67 | * unknown(),
68 | * V)))))
69 | * =:
70 | *
71 | */
72 | goog.Thenable.prototype.then = function(opt_onFulfilled, opt_onRejected,
73 | opt_context) {};
74 |
75 |
76 | /**
77 | * An expando property to indicate that an object implements
78 | * {@code goog.Thenable}.
79 | *
80 | * {@see addImplementation}.
81 | *
82 | * @const
83 | */
84 | goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable';
85 |
86 |
87 | /**
88 | * Marks a given class (constructor) as an implementation of Thenable, so
89 | * that we can query that fact at runtime. The class must have already
90 | * implemented the interface.
91 | * Exports a 'then' method on the constructor prototype, so that the objects
92 | * also implement the extern {@see goog.Thenable} interface for interop with
93 | * other Promise implementations.
94 | * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The
95 | * corresponding class must have already implemented the interface.
96 | */
97 | goog.Thenable.addImplementation = function(ctor) {
98 | goog.exportProperty(ctor.prototype, 'then', ctor.prototype.then);
99 | if (COMPILED) {
100 | ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true;
101 | } else {
102 | // Avoids dictionary access in uncompiled mode.
103 | ctor.prototype.$goog_Thenable = true;
104 | }
105 | };
106 |
107 |
108 | /**
109 | * @param {*} object
110 | * @return {boolean} Whether a given instance implements {@code goog.Thenable}.
111 | * The class/superclass of the instance must call {@code addImplementation}.
112 | */
113 | goog.Thenable.isImplementedBy = function(object) {
114 | if (!object) {
115 | return false;
116 | }
117 | try {
118 | if (COMPILED) {
119 | return !!object[goog.Thenable.IMPLEMENTED_BY_PROP];
120 | }
121 | return !!object.$goog_Thenable;
122 | } catch (e) {
123 | // Property access seems to be forbidden.
124 | return false;
125 | }
126 | };