javascript - Nodejs:使用异步调用按顺序完全执行 websocket 响应
问题描述
下面是我目前正在使用的一个简单示例:一个 websocket 流,它在使用传入数据时执行一些异步调用作为逻辑的一部分。我正在使用 Promise-ified setTimeout 函数模拟异步调用:
function someAsyncWork() {
return new Promise(resolve => {
setTimeout(() => {
resolve('async work done');
}, 5);
});
}
async function msg() {
const msg = await someAsyncWork();
console.log(msg)
}
const main = async() => {
web3.eth.subscribe('pendingTransactions').on("data", async function(tx){
console.log('1st print: ',tx);
await msg();
console.log('2nd print: ',tx);
})
}
main();
运行上面的结果会产生一个控制台输出,如下所示:
1st print: 0x8be207fcef...
1st print: 0x753c308980...
1st print: 0x4afa9c548d...
async work done
2nd print: 0x8be207fcef...
async work done
2nd print: 0x753c308980...
async work done
2nd print: 0x4afa9c548d...
.
.
.
我明白这里发生了什么。执行“第一次打印”,然后等待每个数据响应的异步调用。“第二次打印”仅在“异步工作完成”发生后执行。然而,这并不是我想要的。
我的逻辑有条件,其中每个数据响应将首先使用全局变量来检查条件,然后在满足条件时进行一些异步工作。问题是在某些情况下,某些数据响应会继续执行不应该执行的异步工作:Nodejs 的事件循环没有机会将某些先前数据响应的异步调用从回调队列传输到调用堆栈,因为堆栈忙于处理新的传入数据。这意味着在处理新传入数据之前尚未执行“第二次打印”(全局变量已更新) 。我想 someAsyncWork 仅在 websocket 中有一段空闲时间且没有数据传入时才被解决。
我的问题是:有没有办法确保对每条新数据进行完整、连续的处理?理想情况下,控制台输出看起来像这样:
1st print: 0x8be207fcef...
async work done
2nd print: 0x8be207fcef...
1st print: 0x753c308980...
async work done
2nd print: 0x753c308980...
1st print: 0x4afa9c548d...
async work done
2nd print: 0x4afa9c548d...
.
.
.
解决方案
你可以有一个类似队列的 Promise,它不断累积 Promise 以确保它们按顺序运行:
let cur = Promise.resolve();
function enqueue(f) {
cur = cur.then(f);
}
function someAsyncWork() {
return new Promise(resolve => {
setTimeout(() => {
resolve('async work done');
}, 5);
});
}
async function msg() {
const msg = await someAsyncWork();
console.log(msg);
}
const main = async() => {
web3.eth.subscribe('pendingTransactions').on("data", function(tx) {
enqueue(async function() {
console.log('1st print: ',tx);
await msg();
console.log('2nd print: ',tx);
});
})
}
main();
推荐阅读
- python - 一次在 venv 上运行不同 python 版本的命令 CMD
- javascript - 无法通过道具映射 - React JS/API 调用
- javascript - 如何从 TypeScript 中的地图中的自定义键类型中获取对象?
- wordpress - 如何在 WordPress 页面模板上获取一次数据并在同一页面中使用的多个短代码中访问它
- r - 如何从数据框中的特定列中删除重复值?
- sql - SQL如何获取购买间隔为3个月的帐户ID
- python-3.x - 根据正在检查的条件在 Dataframe 中创建一个新列。我想检查一个列的值是否有多个值,然后为其分配一个值
- javascript - 在 Apps 脚本中的文本前添加分页符
- flutter - 我无法解决这个错误,请帮助我!错误:“StorageUploadTask”不是类型
- java - 如何将项目动态添加到 ListView 的自定义适配器