节点异步循环 - 如何使此代码按顺序运行?

Tsa*_*mba 1 javascript asynchronous node.js

我知道有几篇关于这个的帖子,但根据我发现的那些,这应该可以正常工作。

我想在一个循环中发出一个 http 请求,并且我不希望循环在请求回调被触发之前进行迭代。我正在使用异步库,如下所示:

const async = require("async");
const request = require("request");

let data = [
    "Larry",
    "Curly",
    "Moe"
];

async.forEachOf(data, (result, idx, callback) => {
    console.log("Loop iterated", idx);
    let fullUri = "https://jsonplaceholder.typicode.com/posts";
    request({
        url: fullUri
    }, 
    (err, res, body) => {
        console.log("Request callback fired...");
        if (err || res.statusCode !== 200) return callback(err);
        console.log(result);
        callback();
    });
});
Run Code Online (Sandbox Code Playgroud)

我看到的是:

Loop iterated 0
Loop iterated 1
Loop iterated 2
Request callback fired...
Curly
Request callback fired...
Larry
Request callback fired...
Moe
Run Code Online (Sandbox Code Playgroud)

我需要看到的是:

Loop iterated 0
Request callback fired...
Curly
Loop iterated 1
Request callback fired...
Larry
Loop iterated 2
Request callback fired...
Moe
Run Code Online (Sandbox Code Playgroud)

另外,如果有一个内置的方法来做同样的事情(async/await?Promise?)并且可以删除异步库,那就更好了。

我已经看到了一些很聪明的递归示例,但是当我将其用于更复杂的情况(例如每个循环多次请求调用等)时,我觉得这种方法很难遵循,并且不那么可读。

Nik*_*des 5

你可以async完全放弃并继续async/await很容易地。

承诺您的请求和使用 async/await

只需request变成一个,Promise这样你就可以await了。

更好的是使用request-promise-native已经使用原生 Promise 包装了请求。

串行示例

从那时起,这是一个灌篮async/await

const rp = require('request-promise-native')

const users = [1, 2, 3, 4]
const results = []

for (const idUser of users) {
  const result = await rp('http://foo.com/users/' + idUser)

  results.push(result)
}
Run Code Online (Sandbox Code Playgroud)

并行示例

现在,上述解决方案的问题在于它很慢——请求是串行运行的。大多数时候这并不理想。

如果您不需要下一个请求的前一个请求的结果,只需继续执行 aPromise.all来触发并行请求。

const users = [1, 2, 3, 4]

const pendingPromises = []
for (const idUser of users) {
  // Here we won't `await` on *each and every* request.
  // We'll just prepare it and push it into an Array
  pendingPromises.push(rp('http://foo.com/users/' + idUser))
}

// Then we `await` on a a `Promise.all` of those requests
// which will fire all the prepared promises *simultaneously*, 
// and resolve when all have been completed
const results = await Promise.all(pendingPromises)
Run Code Online (Sandbox Code Playgroud)

错误处理

错误处理async/await由普通try..catch块提供,为简洁起见,我省略了这些块。