我试图解决同样的问题,最后想出了以下承诺包装器:
/**
* wraps a given promise in a new promise with a default onRejected function,
* that handles the promise rejection if not other onRejected handler is provided.
*
* @param customPromise Promise to wrap
* @param defaultOnRejected Default onRejected function
* @returns wrapped promise
*/
export function promiseWithDefaultOnRejected(customPromise: Promise<any>, defaultOnRejected: (_: any) => any): Promise<any> {
let hasCatch = false;
function chain(promise: Promise<any>) {
const newPromise: Promise<any> = new Promise((res, rej) => {
return promise.then(
res,
function(value) {
if (hasCatch) {
rej(value);
} else {
defaultOnRejected(value);
}
},
);
});
const originalThen = newPromise.then;
// Using `defineProperty` to not overwrite `Promise.prototype.then`
Object.defineProperty(newPromise, 'then', {
value: function (onfulfilled: any, onrejected: any) {
const result: Promise<any> = originalThen.call(newPromise, onfulfilled, onrejected);
if (typeof onrejected === 'function') {
hasCatch = true;
return result;
} else {
return chain(result);
}
}
});
return newPromise;
}
return chain(customPromise);
}
这个函数让你用defaultOnRejected 函数包装你的promise,如果没有提供其他处理程序,它将处理被拒绝的promise。例如:
const dontCare = promiseWithDefaultOnRejected(Promise.reject("ignored"), () => {});
结果promise永远不会抛出“Unhandled Promise Rejection”,可以如下使用:
dontCare.then(x=>console.log("never happens")).catch(x=>console.log("happens"));
或
dontCare.then(x=>console.log("never happens"), x=>console.log("happens"));
或者干脆没有onRejected处理程序:
dontCare.then(x=>console.log("never happens")).then(x=>console.log("also never happens"));
此实用程序的一个问题是它无法按预期使用 async/await 语法工作:您需要按如下方式传播和处理“catch”路径:
async () => {
try {
await promiseWithDefaultOnRejected(Promise.reject("ignored"), () => {})
.catch((e) => { throw e; });
} catch (e) {
console.log("happens");
}
}