Node.js中如何处理Unhandled Promise Rejection Warning?调用币安API遇错求解
Node.js对接币安API时超时、未处理Promise拒绝问题的通用处理方案
你当前代码在运行时遇到的pending超时、UnhandledPromiseRejectionWarning,本质是几类逻辑缺失导致的:
- 没有对异步调用做全链路错误捕获,一旦接口请求失败抛出异常,错误会在Promise链中悬空,触发未处理拒绝的警告
- 对406个币种执行循环内逐个await的串行请求模式,总请求数高、单条链路耗时长,极易触发币安的接口频率限制,导致请求被挂起超时
- 没有针对失败请求做重试和异常隔离,单个币种的请求失败会直接拖垮整个批量计算流程
- 代码中存在无意义的冗余操作,对已经是原生对象的balances结果做
JSON.stringify+JSON.parse的循环转换,徒增运行开销
通用处理逻辑
1. 全链路补齐异步错误捕获
所有async函数的调用链都必须覆盖错误捕获,从根源上消除未处理的Promise拒绝:
- 在最外层调用异步函数的位置包裹try/catch,避免异步函数内部抛出的错误穿透到全局
- 循环内每一次接口请求单独做局部错误捕获,实现异常隔离,单个币种的请求失败不会中断其他币种的计算流程
- 在Node.js进程层面监听
unhandledRejection全局事件,兜底捕获所有漏网的异步错误,避免程序无提示退出
2. 优化请求模式解决超时、限流问题
你当前的串行请求模式,每发一个请求都要等上一个响应返回,406个币种跑下来不仅总耗时极长,还很容易触发接口的频率阈值,导致请求被挂起:
- 按照接口的频率限制配置,设置固定大小的并发请求池,在不触发限流的前提下并行发起请求,大幅缩短总耗时
- 给每个接口请求设置明确的超时阈值,超过约定时间未返回响应就直接判定为请求失败,避免请求无限制pending挂起
3. 增加轻量的失败重试机制
大部分偶发的pending错误,都来自临时的网络抖动、接口临时限流:
- 对失败的请求按照间隔逐步拉长的规则做最多3次重试,过滤临时故障的影响
- 对重试依然失败的请求单独记录日志,后续可单独补算,不要阻塞整个批量流程
改造后的参考代码
// 进程级兜底捕获未处理的Promise错误 process.on('unhandledRejection', (reason, promise) => { console.error('捕获到未处理的异步错误:', reason); }); // 基础配置 const REQUEST_CONFIG = { timeout: 10000, // 单请求10秒超时 maxRetry: 3 } binance.balance(async (error, balances) => { if (error) return console.error('获取账户余额失败:', error); const coinList = Object.keys(balances); const coinCount = coinList.length; // 带重试、超时的价格请求封装 async function fetchPriceWithRetry(pair) { let retryTimes = 0; while (retryTimes <= REQUEST_CONFIG.maxRetry) { try { const ticker = await binance.prices(pair); return Number(Object.values(ticker)); } catch (err) { retryTimes++; // 退避等待后重试 await new Promise(resolve => setTimeout(resolve, 1000 * retryTimes)); } } throw new Error(`交易对${pair}连续重试3次仍请求失败`); } async function calculateAllCoinValue() { for (let i = 0; i < coinCount; i++) { const coinName = coinList[i]; const coinAvailableBalance = Object.values(balances[coinName])[0]; const usdtPair = `${coinName}USDT`; try { const usdtRate = await fetchPriceWithRetry(usdtPair); // 无对应USDT交易对的币种单独处理 if (isNaN(usdtRate)) { console.info(`${coinName} 无对应USDT交易对,现有余额${coinAvailableBalance}无法折算USDT价值`); continue; } console.info('交易对', usdtPair, '当前汇率:', usdtRate); console.info(coinName, '可用余额:', coinAvailableBalance); console.info(coinName, '折算USDT价值:', usdtRate * coinAvailableBalance); } catch (err) { console.error(`处理${coinName}价值折算时出错:`, err.message); } } } // 最外层捕获整个批量流程的错误 try { await calculateAllCoinValue(); } catch (err) { console.error('批量价值计算流程异常退出:', err); } });
内容的提问来源于stack exchange,提问作者Soheil
相关产品推荐
相关产品推荐

