// Copyright 2013 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. goog.provide('goog.Thenable'); /** @suppress {extraRequire} */ goog.forwardDeclare('goog.Promise'); // for the type reference. /** * Provides a more strict interface for Thenables in terms of * http://promisesaplus.com for interop with {@see goog.Promise}. * * @interface * @extends {IThenable} * @template TYPE */ goog.Thenable = function() {}; /** * Adds callbacks that will operate on the result of the Thenable, returning a * new child Promise. * * If the Thenable is fulfilled, the {@code onFulfilled} callback will be * invoked with the fulfillment value as argument, and the child Promise will * be fulfilled with the return value of the callback. If the callback throws * an exception, the child Promise will be rejected with the thrown value * instead. * * If the Thenable is rejected, the {@code onRejected} callback will be invoked * with the rejection reason as argument, and the child Promise will be rejected * with the return value of the callback or thrown value. * * @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A * function that will be invoked with the fulfillment value if the Promise * is fulfilled. * @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will * be invoked with the rejection reason if the Promise is rejected. * @param {THIS=} opt_context An optional context object that will be the * execution context for the callbacks. By default, functions are executed * with the default this. * * @return {RESULT} A new Promise that will receive the result * of the fulfillment or rejection callback. * @template VALUE * @template THIS * * When a Promise (or thenable) is returned from the fulfilled callback, * the result is the payload of that promise, not the promise itself. * * @template RESULT := type('goog.Promise', * cond(isUnknown(VALUE), unknown(), * mapunion(VALUE, (V) => * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'), * templateTypeOf(V, 0), * cond(sub(V, 'Thenable'), * unknown(), * V))))) * =: * */ goog.Thenable.prototype.then = function( opt_onFulfilled, opt_onRejected, opt_context) {}; /** * An expando property to indicate that an object implements * {@code goog.Thenable}. * * {@see addImplementation}. * * @const */ goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable'; /** * Marks a given class (constructor) as an implementation of Thenable, so * that we can query that fact at runtime. The class must have already * implemented the interface. * Exports a 'then' method on the constructor prototype, so that the objects * also implement the extern {@see goog.Thenable} interface for interop with * other Promise implementations. * @param {function(new:goog.Thenable,...?)} ctor The class constructor. The * corresponding class must have already implemented the interface. */ goog.Thenable.addImplementation = function(ctor) { // Use bracket notation instead of goog.exportSymbol() so that the compiler // won't create a 'var ctor;' extern when the "create externs from exports" // mode is enabled. ctor.prototype['then'] = ctor.prototype.then; if (COMPILED) { ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true; } else { // Avoids dictionary access in uncompiled mode. ctor.prototype.$goog_Thenable = true; } }; /** * @param {?} object * @return {boolean} Whether a given instance implements {@code goog.Thenable}. * The class/superclass of the instance must call {@code addImplementation}. */ goog.Thenable.isImplementedBy = function(object) { if (!object) { return false; } try { if (COMPILED) { return !!object[goog.Thenable.IMPLEMENTED_BY_PROP]; } return !!object.$goog_Thenable; } catch (e) { // Property access seems to be forbidden. return false; } };