Node.js回调与Promise误区:批量查询XRP余额异常求助
问题根源分析
你的问题核心在于异步操作没有被正确等待,导致API连接在账户查询完成前就被断开了:
- 你用了回调式的
fs.readdir,它不属于Promise链的一部分,所以api.connect()的then块在触发fs.readdir后,会直接执行后续的then(也就是调用api.disconnect()),完全不等目录读取后的账户查询操作完成。 - 就算目录读取完成,
files.forEach里的getAccount是异步Promise操作,但forEach不会等待这些Promise完成,所以所有查询请求还在处理中,连接就被切断了,自然打印不出余额,进程直接结束。
修复方案
我们需要把所有异步操作都纳入Promise链,确保所有账户查询完成后再断开连接。这里有两种写法,你可以选自己习惯的:
方案1:使用async/await(更直观易读)
'use strict'; const RippleAPI = require('ripple-lib').RippleAPI; const testFolder = '/home/ripple/.keystore'; const fs = require('fs').promises; // 改用Promise版本的fs模块 const api = new RippleAPI({server: 'wss://s1.ripple.com'}); function getAccount(address) { console.log("getting info for :" + address); return api.getAccountInfo(address).then(info => { const balance = info.xrpBalance; console.log("balance of " + address + " is " + balance); return balance; }); } // 用async函数包裹,让异步代码同步化写法 api.connect() .then(async () => { // 等待目录读取完成,拿到所有地址文件 const files = await fs.readdir(testFolder); // 遍历每个地址,生成查询余额的Promise数组 const balanceQueries = files.map(address => { console.log(address); return getAccount(address); }); // 等待所有余额查询Promise完成 await Promise.all(balanceQueries); }) .then(() => api.disconnect()) .then(() => console.log("done and disconnected")) .catch(console.error);
方案2:纯Promise链式调用(不用async/await)
如果你还不熟悉async/await,也可以用纯Promise的写法:
'use strict'; const RippleAPI = require('ripple-lib').RippleAPI; const testFolder = '/home/ripple/.keystore'; const fs = require('fs').promises; const api = new RippleAPI({server: 'wss://s1.ripple.com'}); function getAccount(address) { console.log("getting info for :" + address); return api.getAccountInfo(address).then(info => { const balance = info.xrpBalance; console.log("balance of " + address + " is " + balance); return balance; }); } api.connect() .then(() => fs.promises.readdir(testFolder)) // 读取目录,返回Promise给下一个then .then(files => { files.forEach(address => console.log(address)); // 生成所有查询Promise,用Promise.all等待全部完成 return Promise.all(files.map(getAccount)); }) .then(() => api.disconnect()) .then(() => console.log("done and disconnected")) .catch(console.error);
关键改动说明
- 改用
fs.promises.readdir:把回调式的文件读取改成Promise版本,这样它能融入外层的Promise链,确保目录读取完成后再执行后续操作。 - 使用
Promise.all:它会等待传入的所有Promise都成功resolve后才继续执行下一个步骤,这样就能保证所有账户的余额查询都完成后,再断开API连接。 - 移除forEach的异步隐患:forEach不会等待异步操作完成,改用
map生成Promise数组,配合Promise.all就能正确等待所有查询结束。
这样修改后,代码会先连接API,读取目录里的所有地址,逐个查询余额并打印,等所有查询完成后再断开连接,最后打印"done and disconnected",完全符合你的预期。
内容的提问来源于stack exchange,提问作者Codex
相关产品推荐
相关产品推荐

