如何实现入队回调函数,待执行完成后返回结果(订单簿场景)
解决入队异步任务的结果返回问题
嘿,我明白你的问题了——你想把获取订单簿的请求加入队列,等它在队列里执行完之后,再把结果返回给调用getOrderbook的地方对吧?咱们先看看现有代码里的问题,再一步步调整。
现有代码的核心问题
- 队列执行没处理异步逻辑:你的
queueExecutor只是同步调用队列里的函数,但requestOrderbook是异步函数(返回Promise),调用后会直接继续执行下一个队列任务,根本没等当前请求完成。 - 无法追踪入队任务的结果:你把函数推入队列后,
getOrderbook没有任何方式绑定到这个函数的执行结果上,自然没法返回它。 - 多余的
promisify:requestOrderbook本身就是async函数,已经返回Promise了,完全不需要用promisify包装。
方案一:用Promise链实现串行队列(简洁版)
这种方式利用Promise的链式调用,自动维护任务的串行执行顺序,同时让每个getOrderbook调用都能拿到对应任务的结果:
const axios = require("axios"); const moment = require("moment"); const orderbookUpdateTime = {}; const orderbookCache = {}; // 补上实际的订单簿缓存,原来的代码只记录了更新时间 // 维护一个串行执行的Promise链,初始为已完成的Promise let queueChain = Promise.resolve(); async function requestOrderbook(pair) { const response = await axios.post("https://api.kraken.com/0/public/Depth", { pair }); orderbookUpdateTime[pair] = +moment(); const result = response.data.result[pair]; orderbookCache[pair] = result; // 缓存结果 return result; } async function getOrderbook(pair, currentTime = +moment()) { // 优先返回有效缓存(未过期且存在) if (orderbookUpdateTime[pair] && currentTime - orderbookUpdateTime[pair] <= 60000 && orderbookCache[pair]) { return orderbookCache[pair]; } // 缓存无效时,将请求加入串行队列 return new Promise((resolve, reject) => { // 更新队列链,确保任务按顺序执行 queueChain = queueChain .then(() => requestOrderbook(pair)) .then(result => { resolve(result); }) .catch(err => { reject(err); }); }); }
方案二:显式维护队列与任务回调(直观版)
如果你更倾向于直观的队列管理,可以把任务的resolve/reject函数和参数一起存入队列,再用专门的函数处理执行:
const axios = require("axios"); const moment = require("moment"); const orderbookQueue = []; const orderbookUpdateTime = {}; const orderbookCache = {}; let isExecutingQueue = false; // 避免重复启动队列执行 async function requestOrderbook(pair) { const response = await axios.post("https://api.kraken.com/0/public/Depth", { pair }); orderbookUpdateTime[pair] = +moment(); const result = response.data.result[pair]; orderbookCache[pair] = result; return result; } // 负责逐个执行队列任务的函数 async function processOrderbookQueue() { if (isExecutingQueue) return; isExecutingQueue = true; while (orderbookQueue.length > 0) { const { pair, resolve, reject } = orderbookQueue.shift(); try { const result = await requestOrderbook(pair); resolve(result); } catch (error) { reject(error); } } isExecutingQueue = false; } async function getOrderbook(pair, currentTime = +moment()) { // 优先返回有效缓存 if (orderbookUpdateTime[pair] && currentTime - orderbookUpdateTime[pair] <= 60000 && orderbookCache[pair]) { return orderbookCache[pair]; } // 加入队列并返回Promise,等待任务执行完成 return new Promise((resolve, reject) => { orderbookQueue.push({ pair, resolve, reject }); // 启动队列执行 processOrderbookQueue(); }); }
核心逻辑说明
两种方案的本质都是:
- 让
getOrderbook返回一个Promise,这个Promise会在队列里的任务执行完成时被resolve(或reject)。 - 保证队列里的任务串行执行,避免短时间内发送大量请求给API。
- 补上了
orderbookCache来存储实际的订单簿数据,避免重复请求(原来的代码只记录了更新时间,没有缓存结果,这会导致即使缓存未过期也会重新请求)。
现在你调用getOrderbook时,不管是直接返回缓存,还是等待队列里的任务执行,都能拿到正确的订单簿结果啦!
内容的提问来源于stack exchange,提问作者icey-t
相关产品推荐
相关产品推荐

