Javascript 异步/等待函数具有奇怪的行为
我有一个nodejs/javascript应用程序,在async/await方面有一些问题。我已经检查了这里给出的许多建议,但找不到一个适合我的问题。如果有人在那里,我会提前道歉 我有一个从websocket流获取信息的函数。该信息已缓冲,等待进一步处理 每秒使用setTimeout调用处理流中信息的函数(updateOrderBook) 为了能够处理流数据,必须存在订单簿。如果没有,则应创建一个。该函数(createOrderBook)需要从RESTAPI获取数据,这就是我遇到的问题 在updateOrderBook中,我正在等待createOrderBook函数。 createOrderBook依次等待axios返回restapi数据。但在等待此API数据的同时,控制似乎返回到updateOrderBook 那么,我在这里忽略了什么?更重要的是,我如何修复它Javascript 异步/等待函数具有奇怪的行为,javascript,node.js,async-await,Javascript,Node.js,Async Await,我有一个nodejs/javascript应用程序,在async/await方面有一些问题。我已经检查了这里给出的许多建议,但找不到一个适合我的问题。如果有人在那里,我会提前道歉 我有一个从websocket流获取信息的函数。该信息已缓冲,等待进一步处理 每秒使用setTimeout调用处理流中信息的函数(updateOrderBook) 为了能够处理流数据,必须存在订单簿。如果没有,则应创建一个。该函数(createOrderBook)需要从RESTAPI获取数据,这就是我遇到的问题 在upd
const updateOrderBook = () => {
// select the coin at hand
dataBuffer.forEach(async (data, index) => {
dataBuffer.splice(index, 1);
let symbol = data.s.toLowerCase();
if (orderBook.filter(orders => orders.coin === symbol).length === 0) {
await createOrderBook(symbol);
console.log(`${symbol}: Orderbook created`);
}
if (typeof lastUpdateId[symbol] == "undefined") {
console.log(
symbol,
"UNDEFINED",
orderBook.filter(orders => orders.coin === symbol).length === 0
);
}
...
setTimeout(() => updateOrderBook(), 1000);
};
预期日志:
xrpusdt BEFORE ENTERING HIO
xrpusdt HIO
xrpusdt COB
xrpusdt: Orderbook created
实际日志:
xrpusdt ENTERED COB
xrpusdt UNDEFINED false
xrpusdt BEFORE ENTERING HIO
xrpusdt HIO
xrpusdt COB
xrpusdt: Orderbook created
正如您所看到的,我预期会发生未定义的日志,如果在createOrderBook完成之后,在createOrderBook完全完成之前发生,那么问题在于:
dataBuffer.forEach(async (data, index) => {
// ...
});
尽管回调函数是一个异步函数forEach
不会检查此回调的返回值,也不会在调用下一次迭代之前等待返回的承诺
当前,缓冲区中的第一个元素正在等待createOrderBook
完成,而第二个元素跳过if块:
if (orderBook.filter(orders => orders.coin === symbol).length === 0)
这是因为createOrderBook
在等待之前调用orderBook.push(…)
,因此该元素已经被推送,JavaScript引擎将在createOrderBook
中的等待后立即移动到forEach
中的下一个元素
那么你如何解决这个问题呢?最简单的方法是不使用forEach
调用,而是使用。因为您没有创建新的回调函数,所以主函数将等待承诺,并且只有在解决它之后才继续
for (const [index, data] of dataBuffer.entries()) {
// ...
}
要实现这一点,您必须将updateOrderBook
更改为异步函数。上面的代码块假定dataBuffer
是一个数组,如果它是另一个对象,那么您可能需要查看文档,了解如何获取包含索引和元素的迭代器
注意:通过在循环中使用dataBuffer.splice(索引,1)
可以获得一些奇怪的行为。在第一个元素上,索引为0
,第一个元素被删除。这将改变整个阵列。通常,在对数组进行迭代时,不希望对其进行变异。这可以通过以下两种方式之一解决:
使用for(dataBuffer的常量数据)
代替,并在完成迭代后拼接所有元素dataBuffer.slice(0)
(清除数组)
改用while循环
while (dataBuffer.length > 0) {
const data = dataBuffer.shift();
// ...
}
常量字母=[“a”、“b”、“c”、“d”、“e”、“f”、“g”];
for(const[index,letter]of letters.entries()){
控制台日志(索引、字母);
字母.拼接(索引1);
}
控制台日志(字母)代码>问题在于:
dataBuffer.forEach(async (data, index) => {
// ...
});
尽管回调函数是一个异步函数forEach
不会检查此回调的返回值,也不会在调用下一次迭代之前等待返回的承诺
当前,缓冲区中的第一个元素正在等待createOrderBook
完成,而第二个元素跳过if块:
if (orderBook.filter(orders => orders.coin === symbol).length === 0)
这是因为createOrderBook
在等待之前调用orderBook.push(…)
,因此该元素已经被推送,JavaScript引擎将在createOrderBook
中的等待后立即移动到forEach
中的下一个元素
那么你如何解决这个问题呢?最简单的方法是不使用forEach
调用,而是使用。因为您没有创建新的回调函数,所以主函数将等待承诺,并且只有在解决它之后才继续
for (const [index, data] of dataBuffer.entries()) {
// ...
}
要实现这一点,您必须将updateOrderBook
更改为异步函数。上面的代码块假定dataBuffer
是一个数组,如果它是另一个对象,那么您可能需要查看文档,了解如何获取包含索引和元素的迭代器
注意:通过在循环中使用dataBuffer.splice(索引,1)
可以获得一些奇怪的行为。在第一个元素上,索引为0
,第一个元素被删除。这将改变整个阵列。通常,在对数组进行迭代时,不希望对其进行变异。这可以通过以下两种方式之一解决:
使用for(dataBuffer的常量数据)
代替,并在完成迭代后拼接所有元素dataBuffer.slice(0)
(清除数组)
改用while循环
while (dataBuffer.length > 0) {
const data = dataBuffer.shift();
// ...
}
常量字母=[“a”、“b”、“c”、“d”、“e”、“f”、“g”];
for(const[index,letter]of letters.entries()){
控制台日志(索引、字母);
字母.拼接(索引1);
}
控制台日志(字母)
dataBuffer似乎包含一些在第一次迭代后未通过筛选条件的数据。因此,异步if
按预期运行,然后同步if
运行并创建您看到的竞争条件。@RandyCasburn-我还不明白,您能更深入地解释一下吗?似乎dataBuffer包含一些在第一次迭代后未通过筛选条件的数据。因此,异步if
按预期运行,然后同步if
运行并创建您看到的竞争条件。@RandyCasburn-我还不明白,您能更深入地解释一下吗?@MPL只是为了确保我添加了一个代码块,说明结果如何