for循环不等待异步代码完成

时间:2020-03-19 11:37:42

标签: javascript node.js

我有一个for循环,其中有一个函数调用,并且该函数还具有一些异步代码。现在的问题是,for循环不会等待异步代码从嵌套函数调用中返回并继续进行迭代。

函数aFunctionThatRunsAsync来自我无法控制的库。

下面是所有代码。

// arr.length = 2

for (let i in arr) {
  console.log(i, 'i1')

  functionOne(arr[i], i, (err, res) => {
    console.log(res)
  })
}

function functionOne(inp, idx, callback) {
  console.log(idx, 'i1')
  const processor = aFunctionThatRunsAsync(inp, err => {
    if (err) return callback(err);
  });

  processor.on('complete', data => {
    console.log(data, idx, 'i3')
    return callback(null, data)
  });
}

问题:

执行代码后,日志如下所示:

0 i1 // expected
0 i2 // expected
1 i1 // unexpected, expected to have logged: data(obj) i3
1 i2 // unexpected, expected to have logged: 1 i1

最后登录:

data(obj) 0 i3
data(obj) 1 i3 // Not always in the same order

我希望for循环等待异步代码返回/记录并以正确的顺序同步运行,以便最终输出如下所示:

0 i1
0 i2
data(obj) 0 i3
1 i1
1 i2
data(obj) 1 i3

1 个答案:

答案 0 :(得分:3)

for-in中的代码没有任何内容可以等待这些回调。

functionOne中的代码看起来不是基于承诺的,因此,除非您想更改该代码,否则需要等待回调后才能开始下一次迭代,如下所示:

process(0);
function process(i) {
  if (i < arr.length) {
    console.log(i, 'i1')
    functionOne(arr[i], i, (err, res) => {
      if (err) {
        console.error(err);
        // I assume you don't want to continue here
      } else {
        console.log(res);
        process(i + 1);
      }
    });
  }
}

或者,您可以让functionOne返回承诺:

function functionOne(inp, idx) {
  return new Promise((resolve, reject) {
    console.log(idx, 'i1')
    const processor = aFunctionThatReturnsAPromise(inp, err => {
      if (err) return reject(err);
    });

    processor.on('complete', data => {
      console.log(data, idx, 'i3');
      resolve(data);
    });
  })
}

然后:

let promise = Promise.resolve();
for (let i = 0; i < arr.length; ++i) {
    promise = promise.then(() => (
        functionOne(arr[i], i).then(res => {
            console.log(res);
        })
    ));
}
promise.catch(error => console.error(error));

请注意,let内的for很重要。它不能var,并且必须在for内部。那是因为我们需要传递给then的回调,以便对该循环进行 close i的循环迭代,如上所述,它会与let一起使用与var

async函数中使用起来会更容易:

// In an `async` function
try {
    for (let i = 0; i < arr.length; ++i) {
        console.log(await functionOne(arr[i], i));
    }
} catch (error) {
    console.error(error);
}