I'm updating some old code (not mine originally) that uses Bluebird promises. I'd rather use native ES6 Promises instead, but the old code uses a function Promise doesn't have, one to check if promises have been settled.
This is related to a similar question (Is there a way to tell if an ES6 promise is fulfilled/rejected/resolved?), but the solution given there is very different, so I wanted to know if the following code is a reasonable approach to the problem.
export class QueryablePromise<T> extends Promise<T> {
private _isRejected = false;
private _isResolved = false;
private _isSettled = false;
then<TResult1 = T, TResult2 = never>(
onResolved?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): Promise<TResult1 | TResult2> {
const newResolved = onResolved && ((value: T): TResult1 | PromiseLike<TResult1> => {
this._isResolved = true;
this._isSettled = true;
return onResolved(value);
});
const newRejected = onRejected && ((reason: any): TResult2 | PromiseLike<TResult2> => {
this._isRejected = true;
this._isSettled = true;
return onRejected(reason);
});
return super.then(newResolved, newRejected);
}
catch<TResult = never>(
onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null
): Promise<T | TResult> {
const newRejected = onRejected && ((reason: any): TResult | PromiseLike<TResult> => {
this._isRejected = true;
this._isSettled = true;
return onRejected(reason);
});
return super.catch(newRejected);
}
finally(
onFinally?: (() => void) | undefined | null
): Promise<T> {
const newFinally = onFinally && ((): void => {
this._isSettled = true;
return onFinally();
});
return super.finally(newFinally);
}
get isRejected(): boolean { return this._isRejected; }
get isResolved(): boolean { return this._isResolved; }
get isSettled(): boolean { return this._isSettled; }
}
Basically I'm wrapping each callback passed to then, catch, and finally in another function which sets the appropriate flags and then calls the original callback. Flags could easily be set redundantly many times this way, but I don't see that as being much of a problem.
I tried to think of a way to solve this problem using the constructor for my promise subclass, and somehow put a wrapper around the original executor argument to intercept invocations of resolve and reject, but couldn't quite put my head around a way to implement that type of solution.
I also tried simply adding my own separate then, catch, and finally callbacks in a constructor for this subclass, with each having nothing to do but set my status flags, but oddly enough that resulted in a stack overflow, the constructor being called recursively until it blew up.