Symbol SDK获取账户余额时出现未处理Promise拒绝警告问题
解决Symbol SDK查询余额时的UnhandledPromiseRejectionWarning问题
看起来你遇到的UnhandledPromiseRejectionWarning是因为userBalance函数里手动封装Promise的方式有问题——你同时混用了RxJS的错误处理和手动Promise的reject,导致有些错误没有被正确关联到你创建的Promise上,进而出现未捕获的拒绝。
问题根源拆解
- 在
userBalance中,你手动创建了Promise,但在RxJS的catchError里调用reject(err)后又返回了of(err),这会让Observable继续触发后续的subscribe回调,可能导致resolve和reject被多次调用,或者错误没有被正确绑定到当前Promise。 - 手动封装Promise包裹Observable完全没必要,RxJS本身提供了
toPromise()方法,可以直接把Observable转换成Promise,错误处理会更统一。
修改后的完整代码
import * as SymbolSdk from 'symbol-sdk'; import { catchError } from 'rxjs/operators'; const nodeUrl = 'http://localhost:3000'; // 重写userBalance,用RxJS的toPromise替代手动封装Promise export async function userBalance(userAddress: SymbolSdk.Address, mosaicId: SymbolSdk.MosaicId): Promise<SymbolSdk.UInt64> { const repositoryFactory = new SymbolSdk.RepositoryFactoryHttp(nodeUrl); const accountHttp = repositoryFactory.createAccountRepository(); try { const accountInfo = await accountHttp.getAccountInfo(userAddress) .pipe( catchError((err) => { // 直接抛出错误,让外层try/catch捕获 throw err; }) ) .toPromise(); // 转换为Promise // 查找目标mosaic的余额 const targetMosaic = accountInfo.mosaics.find(mosaic => mosaicId.equals(mosaic.id)); return targetMosaic?.amount || new SymbolSdk.UInt64([0, 0]); } catch (err) { // 统一处理错误,抛出后会被调用方的catch捕获 throw err; } } if (require.main === module) { const promiseList = []; const users = ["TCC4A2H6VX4MVBYHBG33JRCL7SI4Z7OKSKUQRNXS", "TBHE2SZCMVGQTDDVSMM6G7KE33IWCXA726WXEV3H", "TBKFTBO4X5EIEHE4LDWVFALJGQU3HCVTAHN2NXCH", "TCWUJ4ENXWC4QYJ4N7ESVUHTBXL6IJ4TTPNFME3F", "TC2X5PCGSOEGX6TPZYTZQZYJBOP2QOPDC4VQ5GCK"]; const rawMosaicId = "0874BB5FEAAA53C4"; // 简化promise创建逻辑,去掉不必要的手动Promise封装 users.forEach(user => { const promise = (async () => { try { const address = SymbolSdk.Address.createFromRawAddress(user); const mosaicId = new SymbolSdk.MosaicId(rawMosaicId); const amount = await userBalance(address, mosaicId); return [user, amount, mosaicId] as [string, SymbolSdk.UInt64, SymbolSdk.MosaicId]; } catch (err) { throw err; } })(); promiseList.push(promise); }); Promise.allSettled(promiseList).then((values) => { console.log("Chain over"); values.forEach((settled) => { if (settled.status === "fulfilled") { const [user, amount, mosaicId] = settled.value; console.log(`User ${user}, amount of ${mosaicId.toHex()}: ${amount.toString()}`); } else { console.log(`Failed to get balance for user, reason: ${settled.reason}`); } }); }).catch(console.error); }
关键改动说明
重构
userBalance函数:- 移除手动创建的Promise,改用RxJS的
toPromise()方法将Observable转为Promise,错误会自动被Promise的catch捕获。 - 用
try/catch统一处理异步错误,避免RxJS和手动Promise的错误处理冲突。 - 用
find替代循环查找mosaic,代码更简洁高效。
- 移除手动创建的Promise,改用RxJS的
简化主逻辑中的Promise创建:
- 去掉不必要的手动Promise封装,直接用async函数返回Promise,错误会自动被
Promise.allSettled处理。
- 去掉不必要的手动Promise封装,直接用async函数返回Promise,错误会自动被
这样修改后,所有错误都会被正确捕获,不会再出现UnhandledPromiseRejectionWarning,同时逻辑更清晰,符合Promise和RxJS的最佳实践。
内容的提问来源于stack exchange,提问作者mpsido
相关产品推荐
相关产品推荐

