简体   繁体   English

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

[英]for loop doesn't wait for async code to finish

I have a for loop in which there is a function call and that function further has some async code.我有一个 for 循环,其中有一个函数调用,并且该函数还有一些异步代码。 Now the issue is that the for loop doesn't wait for the async code to return from the nested function call and continues iterating.现在的问题是 for 循环不等待异步代码从嵌套函数调用返回并继续迭代。

The function aFunctionThatRunsAsync comes from a library that I have no control over.函数aFunctionThatRunsAsync来自一个我无法控制的库。

Below is all the code.下面是全部代码。

// 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)
  });
}

Problem:问题:

The log looks like this after the execution of the code:代码执行后的日志是这样的:

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

And finally logs:最后记录:

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

I want the for loop to wait for the async code to return/log and run synchronously in the correct order so the final output look like this:我希望 for 循环等待异步代码返回/记录并以正确的顺序同步运行,因此最终输出如下所示:

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

That code doesn't have anything in the for-in to make it wait for those callbacks.该代码在for-in中没有任何内容使其等待这些回调。

The code in functionOne doesn't look promise-based, so unless you want to change that code, you need to wait for the callback before starting the next iteration, something like this: functionOne中的代码看起来不是基于 promise 的,因此除非您想更改该代码,否则您需要在开始下一次迭代之前等待回调,如下所示:

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);
      }
    });
  }
}

Alternatively, you could make functionOne return a promise:或者,您可以让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);
    });
  })
}

Then:然后:

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));

Note that the let inside the for there is important.请注意, for there 里面的let很重要。 It can't be var , and it has to be inside the for .不能var ,它必须在for That's because we need the callback we pass to then to close over the i for that loop iteration, which it will with let as above but wouldn't with var .那是因为我们需要传递给then的回调来关闭该循环迭代的i ,它会像上面那样使用let但不会使用var

It would be easier to use in an async function: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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM