回调转异步遇阻:Coinbase API异步改造失败求助
解决回调转async/await的问题,修复Coinbase API调用错误
首先,咱们来拆解你遇到的两个核心问题:
问题1:Cannot read property 'account' of undefined
你这里犯了一个小错误:await API.getAccount(API_Account_BTC)返回的直接就是account对象,不需要再额外加.account层级。原来的回调代码里,API.getAccount的第二个参数里的account就是返回的结果,所以async版本里const account = await ...之后,直接用account.getTransactions就对了。
问题2:no callback - check method signature
这个错误说明你用的Coinbase库的方法只支持回调模式,不原生返回Promise,所以直接用await会报错——因为await后面必须是一个Promise对象。解决办法是把回调风格的函数包装成Promise版本。
完整的改造方案
下面是修正后的可运行代码,我会逐段解释:
首先,如果你用的是Node.js,可以用内置的util.promisify把回调函数转成Promise;如果环境不支持,也可以手动包装。
const util = require('util'); // Node.js内置工具库 // 先把回调风格的方法转成Promise版本 // 包装API.getAccount const getAccountAsync = util.promisify(API.getAccount); // 包装account.getTransactions(因为它的回调有三个参数,promisify无法直接处理) function getTransactionsAsync(account, pagination = null) { return new Promise((resolve, reject) => { account.getTransactions(pagination, (err, data, pagination) => { if (err) reject(err); else resolve({ data, pagination }); }); }); } async function Test() { let TXs = []; const Array_Pending_API = [0]; try { // 获取账户,现在可以用await了 const account = await getAccountAsync(API_Account_BTC); // 获取三次交易数据,对应你原来的逻辑 const { data: tx1Data, pagination: pagination1 } = await getTransactionsAsync(account); TXs = TXs.concat(tx1Data); const { data: tx2Data, pagination: pagination2 } = await getTransactionsAsync(account, pagination1); TXs = TXs.concat(tx2Data); const { data: tx3Data } = await getTransactionsAsync(account, pagination2); TXs = TXs.concat(tx3Data); // 筛选未确认的转出交易 for (const tx of TXs) { if (tx.type === "send" && tx.amount.amount < 0 && tx.network.status !== "confirmed") { Array_Pending_API.push(-Number(tx.amount.amount)); } } // 计算总和 Pending_API = Array_Pending_API.reduce(getSum); } catch (err) { console.log("Failed to get transactions:", err); Pending_API = 0; } } // 调用Test函数时要处理Promise,避免未捕获拒绝 // Test().catch(err => console.error("Test function error:", err));
关键细节解释
回调转Promise:
- 对于
API.getAccount,直接用util.promisify就可以,因为它符合Node.js的标准回调格式(最后一个参数是(err, result))。 - 对于
account.getTransactions,因为它的回调有三个参数(err, data, pagination),util.promisify只会返回第一个成功值(也就是data),所以我们手动包装Promise,把data和pagination一起返回,这样才能处理分页。
- 对于
错误处理:
- 把所有可能出错的await操作放在
try/catch里,和你原来的try/catch逻辑对应,捕获API调用的错误。 - 调用
Test()函数的时候,一定要用.catch()处理可能的未捕获错误,避免出现UnhandledPromiseRejectionWarning。
- 把所有可能出错的await操作放在
代码优化:
- 把原来的for循环改成
for...of,更简洁易读。 - 用对象解构获取data和pagination,代码更清晰。
- 把原来的for循环改成
深入学习async/await的要点
- async函数的本质:async函数执行后返回一个Promise,不管你return什么值,都会被包装成
Promise.resolve(值)。 - await的要求:await后面必须是一个Promise对象,如果不是,会自动被包装成Promise。
- 回调转Promise的通用方法:
- 标准Node.js回调(err优先):用
util.promisify。 - 非标准回调:手动用
new Promise((resolve, reject) => { ... })包裹,在回调里调用resolve或reject。
- 标准Node.js回调(err优先):用
- 错误处理:
- 要么在async函数内部用try/catch捕获await的错误。
- 要么在调用async函数的时候用
.catch()处理。 - 一定要处理所有Promise的拒绝,否则Node.js新版本会直接终止进程。
内容的提问来源于stack exchange,提问作者Wannes
相关产品推荐
相关产品推荐

