为什么 async.series 只产生一个输出

Why async.series only produce one output?

本文关键字:一个 输出 async series 为什么      更新时间:2023-09-26

>我有以下代码,它使用 gotasync.seriesrandomuser API发出 10 个请求。出于某些原因,这只给了我一个输出。我该如何解决这个问题?

const got = require('got');
const async = require('async');
var tenOperations = [];
for(var i = 0; i < 10; i++) {
  tenOperations.push(doRequest);
}
function doRequest(callback) {
  got('https://randomuser.me/api/')
  .then(response => {
    console.log(response.body);
  })
  .catch(error => {
    console.log(error.response.body);
  });
};
async.series(tenOperations, function(err, results) {
  if(err) console.log(err);
  console.log(results);
});

Here is the sample output

     {
    "results": [
        {
            "user": {
                "gender": "female",
                "name": {
                    "title": "miss",
                    "first": "غزل",
                    "last": "كامياران"
                },
                "location": {
                    "street": "6186 آزادی",
                    "city": "رشت",
                    "state": "تهران",
                    "zip": 64318
                },
                "email": "غزل.كامياران@example.com",
                "username": "goldenpanda201",
                "password": "muscles",
                "salt": "OStU2tyA",
                "md5": "92ac8a84380a24785597d0e916b0174e",
                "sha1": "93f6e830538dbc557017011583cca3b5e527f854",
                "sha256": "99a4c35237b1ebe276732fbf62efca24fd457428853de8a967dd465b80b82f0f",
                "registered": 1352433856,
                "dob": 1370066399,
                "phone": "053-14062122",
                "cell": "0929-641-1309",
                "picture": {
                    "large": "https://randomuser.me/api/portraits/women/48.jpg",
                    "medium": "https://randomuser.me/api/portraits/med/women/48.jpg",
                    "thumbnail": "https://randomuser.me/api/portraits/thumb/women/48.jpg"
                }
            }
        }
    ]
}

如果您只想按顺序向同一 API 发出十个请求(一个接一个,而不是并行),您可以这样做:

const got = require('got');
function runSequence(url, num) {
    let cntr = 0;
    let results = [];
    return new Promise(function(resolve, reject) {
        function checkDone(data) {
            ++cntr;
            results.push(data);
            if (cntr < num) {
                next();
            } else {
                resolve(results);
            }
        }
        function next() {
            got(url).then(response => {
                console.log(response.body);
                checkDone(response.body);
            }).catch(error => {
                console.log(error.response.body);
                checkDone(null);
            });
        }
        next();
    });
}
runSequence('https://randomuser.me/api/', 10).then(function(results) {
    // access array of results here
});

如果 API 调用不必一次执行一个,并且您可以同时将它们全部运行,则可以执行以下操作:

function runParallel(url, num) {
    let promises = [];
    for (let i = 0; i < num; i++) {
        promises.push(got(url));
    }
    return Promise.all(promises);
}
runParallel('https://randomuser.me/api/', 10).then(function(results) {
    // access array of results here
});
注意:并行选项在出现第一个错误时

中止,而此处显示的两个序列选项在出现错误时继续。 可以将其更改为其他行为。 您没有指定所需的内容。


下面是运行序列的略有不同的方法:

function runSequence(url, num) {
    let cntr = 0;
    let results = [];
    function checkDone(data) {
        ++cntr;
        results.push(data);
        if (cntr < num) {
            return next();
        } else {
            return results;
        }            
    }
    function next() {
        return got(url).then(response => {
            return checkDone(response.body);
        }).catch(error => {
            return checkDone(null);
        });
    }
    return next();
}

下面是一个通用函数,用于重复某些异步操作 N 次。 您传入异步函数(返回一个 promise),您希望它按顺序重复的次数以及您希望它在出错时继续还是在错误时中止。

// pass a function that returns a promise
function repeatSequence(fn, num, continueOnError) {
    let cntr = 0;
    let results = [];
    checkDone(data) {
        ++cntr;
        results.push(data);
        if (cntr < num) {
            return next();
        } else {
            return results;
        }
    }
    function next() {
        return fn().then(checkDone).catch(function(err) {
            if (continueOnError) {
                return checkDone(null);
            } else {
                // reject on error
                throw err;
            }
        });
    }
    return next();
}

而且,如果您使用Bluebird Promise库,则可以使用以下Promise.mapSeries()

function repeatSequence(fn, num, continueOnError) {
    var array = new Array(num);
    return Promise.mapSeries(array, function () {
        return fn().catch(function (err) {
            if (continueOnError) {
                return null;
            } else {
                throw (err);
            }
        });
    });
}

或者,如果您不想要continueOnError选项,它就会变成这样:

function repeatSequence(fn, num) {
    var array = new Array(num);
    return Promise.mapSeries(array, fn);
}

我必须同意Bergi的观点,即我们不能将回调与承诺混为一谈。尽管它们都是异步机制,但这两种结构中的每一个在本质上和哲学上都不应被一视同仁。

然而,正如jfriend00指出的那样,主要问题是在每一步中都没有调用"回调"。在使用非承诺库时,这将是正确的解决方案。

溶液

请在下面找到我的修改。本质是:

  1. 此解决方案是有关如何仅使用 promise 实现它的示例。
  2. 像 async-q 这样的端口可能会帮助你更好地使用现有库。

    const got = require('got');
    const async_q = require('async-q');
    var tenOperations = [];
    for(var i = 0; i < 10; i++) {
        tenOperations.push(doRequest);
    }
    function doRequest() {
        return got('https://randomuser.me/api/')
        .then(response => {
            console.log('resp', response.body);
            return JSON.parse(response.body);
        })
        .catch(error => {
            console.log('error', error.response.body);
            return error.response.body;
        });
    }
    async_q
    .series(tenOperations)
    .then (results => {
        console.log('results', results);
    })
    .done();