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
15goog.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 */
27goog.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 */
57goog.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 */
69goog.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 */
82goog.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 */
98goog.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};