Node.js Promise链式调用双实例同时reject未处理报错如何解决
问题原因
- 你当前代码中
verifyStockP和verifyCardP两个Promise实例在submitOrder函数调用时就会立即同步执行,不会等待前者执行完成 - 当两个Promise同时reject时,
verifyStockP的reject会触发链式调用末尾的catch,但是此时verifyCardP的reject没有绑定任何catch处理函数——因为verifyStockPreject后不会进入第一个then,也就不会把verifyCardP挂载到后续的Promise链式中,所以就抛出了未处理的Promise拒绝警告。
解决方案
方案1:串行执行校验(适合业务逻辑要求先验库存、再验卡,库存不足无需验卡的场景)
不要提前创建verifyCardP,而是在库存校验通过的then回调中再创建并返回,这样库存校验失败时卡校验根本不会执行,自然不会有未处理的reject:
const submitOrder = (prod, prodQuantity, userCardDigits) => { const currentStock = 10; const verifyStockP = new Promise((resolve, reject) => { if(prodQuantity <= currentStock) { resolve('stock available') } else { reject('out of stock') } }) verifyStockP .then((resolvedVal) => { console.log(resolvedVal); // 库存校验通过后再创建卡校验Promise const verifyCardP = new Promise((resolve,reject) => { let cardDigits = 16; if (cardDigits === userCardDigits) { resolve('card valid') } else { reject('card invalid') } }) return verifyCardP }).then((resolvedVal) => { console.log('card valid') emitter.emit('order_successful', prod) }).catch((error) => { console.log(error) emitter.emit('order_failed', prod) }) }
方案2:并行执行校验(适合需要同时跑两个校验、提高执行效率的场景)
用Promise.all来统一管理两个并行的Promise,所有Promise的状态都会被Promise.all监听,任意reject都会进入其绑定的catch,不会出现未处理的拒绝:
const submitOrder = (prod, prodQuantity, userCardDigits) => { const currentStock = 10; const verifyStockP = new Promise((resolve, reject) => { if(prodQuantity <= currentStock) { resolve('stock available') } else { reject('out of stock') } }) const verifyCardP = new Promise((resolve,reject) => { let cardDigits = 16; if (cardDigits === userCardDigits) { resolve('card valid') } else { reject('card invalid') } }) Promise.all([verifyStockP, verifyCardP]) .then(([stockRes, cardRes]) => { console.log(stockRes) console.log(cardRes) emitter.emit('order_successful', prod) }).catch((error) => { console.log(error) emitter.emit('order_failed', prod) }) }
如果需要获取所有校验的错误信息而不是只拿到第一个reject的结果,可以用Promise.allSettled,再自行遍历所有结果的状态做处理。
其他代码优化建议
- 把校验逻辑抽成独立的可复用函数,不要硬编码在submitOrder里,比如把verifyStock、verifyCard抽成单独的返回Promise的函数,后续维护更方便
- 如果当前EventEmitter只是用来处理订单成功/失败的回调,完全可以直接在Promise的then/catch里执行对应的逻辑,没必要额外引入事件机制,减少不必要的复杂度;如果后续有多个模块需要监听订单事件可以保留
- 建议把错误信息封装成Error实例而不是直接返回字符串,后续排查问题可以拿到错误栈信息,更方便定位,比如
reject(new Error('out of stock'))替代reject('out of stock')
内容的提问来源于stack exchange,提问作者juanvicareer
相关产品推荐
相关产品推荐

