Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 异步/等待函数具有奇怪的行为_Javascript_Node.js_Async Await - Fatal编程技术网

Javascript 异步/等待函数具有奇怪的行为

Javascript 异步/等待函数具有奇怪的行为,javascript,node.js,async-await,Javascript,Node.js,Async Await,我有一个nodejs/javascript应用程序,在async/await方面有一些问题。我已经检查了这里给出的许多建议,但找不到一个适合我的问题。如果有人在那里,我会提前道歉 我有一个从websocket流获取信息的函数。该信息已缓冲,等待进一步处理 每秒使用setTimeout调用处理流中信息的函数(updateOrderBook) 为了能够处理流数据,必须存在订单簿。如果没有,则应创建一个。该函数(createOrderBook)需要从RESTAPI获取数据,这就是我遇到的问题 在upd

我有一个nodejs/javascript应用程序,在async/await方面有一些问题。我已经检查了这里给出的许多建议,但找不到一个适合我的问题。如果有人在那里,我会提前道歉

我有一个从websocket流获取信息的函数。该信息已缓冲,等待进一步处理

每秒使用setTimeout调用处理流中信息的函数(updateOrderBook)

为了能够处理流数据,必须存在订单簿。如果没有,则应创建一个。该函数(createOrderBook)需要从RESTAPI获取数据,这就是我遇到的问题

在updateOrderBook中,我正在等待createOrderBook函数。 createOrderBook依次等待axios返回restapi数据。但在等待此API数据的同时,控制似乎返回到updateOrderBook

那么,我在这里忽略了什么?更重要的是,我如何修复它

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只是为了确保我添加了一个代码块,说明结果如何