如何实现 BluebirdJS 同步检查扩展原生 Promise
Posted
技术标签:
【中文标题】如何实现 BluebirdJS 同步检查扩展原生 Promise【英文标题】:How to implement BluebirdJS synchronous inspection extending a native Promise 【发布时间】:2022-01-24 03:24:19 【问题描述】:我正在更新一些使用 Bluebird 承诺的旧代码(最初不是我的)。我宁愿使用原生 ES6 Promise
s 代替,但旧代码使用 Promise
没有的函数,用于检查承诺是否已解决。
这与一个类似的问题(Is there a way to tell if an ES6 promise is fulfilled/rejected/resolved?)有关,但那里给出的解决方案非常不同,所以我想知道以下代码是否是解决问题的合理方法。
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;
基本上,我将传递给then
、catch
和finally
的每个回调包装在另一个函数中,该函数设置适当的标志,然后调用原始回调。以这种方式可以轻松地多次重复设置标志,但我认为这不是什么大问题。
我试图想出一种方法来使用我的 promise 子类的构造函数来解决这个问题,并以某种方式在原始 executor 参数周围放置一个包装器以拦截 resolve
和 reject
的调用,但不能完全放我想到了一种实现这种解决方案的方法。
我还尝试在该子类的构造函数中简单地添加我自己单独的 then
、catch
和 finally
回调,每个回调除了设置我的状态标志外无事可做,但奇怪的是导致了堆栈溢出,构造函数被递归调用,直到它崩溃。
【问题讨论】:
嗨,尝试同步评估 Promise 的状态一次又一次。至少在我寻找解决方案时,是因为我围绕 Promises 的整个设计都是错误的。有关更多信息,请参阅此帖子:softwareengineering.stackexchange.com/questions/309511/… 我没有发现任何需要测试我在自己的代码中创建的 Promise 的状态,显然有很多方法可以避免这样做,但在这种情况下我正在尝试更接近我正在修改的原始代码的方法。 "如果以下代码是解决问题的合理方法。" - 否。正确的解决方案是重写使用承诺不同步检查其状态的代码。为什么你认为你需要这样做? "我也尝试在这个子类的构造函数中简单地添加我自己单独的then
回调,但奇怪的是导致堆栈溢出" - 这是因为 @ 987654335@构造同一个子类的新promise
【参考方案1】:
此代码看起来并不可靠。你需要记住 Promises 在创建时会自动解析。
使用上面的代码,这个简单的测试会失败:
const a = new QueryablePromise((res, rej) =>
setTimeout(() => console.log('resolved'); res(), 100)
);
setTimeout(() =>
console.log(a.isSettled)
, 500);
会输出
// resolved
// false
需要考虑所有情况,不仅是在调用then
、catch
或finally
时。我可能会重写构造函数并像这样包装resolve
和reject
函数:
class QueryablePromise<T> extends Promise<T>
private _isRejected: boolean | undefined;
private _isResolved: boolean | undefined;
private _isSettled: boolean | undefined;
constructor (fn: (res: (value: T | PromiseLike<T>) => void, rej: (reason?: any) => void) => void)
super((resolve, reject) => fn(
value =>
resolve(value)
if (value instanceof Promise || typeof value === 'object' && typeof (value as any).then === 'function')
(value as any).then(() =>
this._isResolved = true;
this._isSettled = true;
);
else
this._isResolved = true;
this._isSettled = true;
,
reason =>
reject(reason)
this._isRejected = true;
this._isSettled = true;
,
));
this._isRejected = false;
this._isResolved = false;
this._isSettled = false;
get isRejected(): boolean return this._isRejected!;
get isResolved(): boolean return this._isResolved!;
get isSettled(): boolean return this._isSettled!;
【讨论】:
谢谢!正如您所描述的承诺自动解决,我没有看到任何问题,所以我认为我的原始代码没有错误,但您的这种方法是我最初希望做的。在super(...)
调用中引用 this
时,我不断收到错误消息。然而,你在这里做的方式解决了我遇到的问题。好东西!
奇怪的是,如果不调用 then
,您就看不到 isSettled
为假。但我很高兴代码对你有用。 :)
这个解决方案还是错误的。 QueryablePromise.resolve(new Promise()).isSettled
将返回 true
尽管承诺仍在等待中。
@Bergi 在解析 Promise 时,我更新了该类以涵盖 thenable
值。可能需要进行一些调整以涵盖特定场景,但是,如果需要涵盖所有场景的整体解决方案,则最好坚持使用 BluebirdJS。以上是关于如何实现 BluebirdJS 同步检查扩展原生 Promise的主要内容,如果未能解决你的问题,请参考以下文章