/**
* 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() {}