/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow * @format */ 'use strict'; type PromiseLike<R> = { catch<U>(onReject?: (error: any) => ?Promise<U> | U): Promise<U>, then<U>( fulfilled?: (R) => Promise<U> | U, rejected?: (error: any) => Promise<U> | U, ): Promise<U>, }; /** * A promise-like object that only creates the underlying value lazily * when requested. */ exports.LazyPromise = class LazyPromise<T> { _promise: PromiseLike<T>; constructor(factory: () => PromiseLike<T>) { //$FlowIssue #16209141 Object.defineProperty(this, '_promise', { configurable: true, enumerable: true, get: () => (this._promise = factory()), set: value => Object.defineProperty(this, '_promise', {value}), }); } then<U>( fulfilled?: (value: T) => Promise<U> | U, rejected?: (error: any) => Promise<U> | U, ): Promise<U> { return this._promise.then(fulfilled, rejected); } catch<U>(rejected?: (error: any) => ?Promise<U> | U): Promise<U> { return this._promise.catch(rejected); } }; /** * A promise-like object that allows only one `.then()` handler to access * the wrapped value simultaneously. Can be used to lock resources that do * asynchronous work. */ exports.LockingPromise = class LockingPromise<T> { _gate: PromiseLike<any>; _promise: PromiseLike<T>; constructor(promise: PromiseLike<T>) { this._gate = this._promise = promise; } then<U>( fulfilled?: (value: T) => Promise<U> | U, rejected?: (error: any) => Promise<U> | U, ): Promise<U> { const whenUnlocked = () => { const promise = this._promise.then(fulfilled, rejected); this._gate = promise.then(empty); // avoid retaining the result of promise return promise; }; return this._gate.then(whenUnlocked, whenUnlocked); } catch<U>(rejected?: (error: any) => ?Promise<U> | U): Promise<U> { return this._promise.catch(rejected); } }; function empty() {}