简体   繁体   English

节点-async.map如何工作?

[英]node - how does async.map work?

After reading about async , I assumed the code below would output to the console the total of all values returned from the http/API call; 在阅读了有关async ,我假设下面的代码会将从http / API调用返回的所有值的总和输出到控制台。 but it seems to fire immediately after the first http call returns, and only shows a 'total' value equal to the first value returned from the API. 但它似乎在第一个http调用返回后立即触发,并且仅显示等于从API返回的第一个值的“总计”值。

Where is my misunderstanding about how async.map works? 我对async.map的工作方式有何误解?

var http = require('https');
const
async = require('async');

var MongoClient = require('mongodb').MongoClient;
var dbUrl = "mongodb://localhost:27017/";

var total = 0;

var tokens = [ {
    name : "tron"
}, {
    name : 'cardano'
}, {
    name : 'nucleus-vision'
}, {
    name : 'ripple'
}, {
    name : 'litecoin'
}, {
    name : 'havven'
}];

function run() {

    doStuff();
    setInterval(doStuff, 1 * 60 * 1000);
};

function doStuff() {

    total = 0;

    async.map(tokens, httpGet, function (value){
          console.log('async done ', total);
        });

}

function httpGet(token, callback) {

    var url = 'https://api.coinmarketcap.com/v1/ticker/' + token.name;
    http.get( url,
        function(res) {
            var body = '';

            res.on('data', function(chunk) {
                body += chunk;
            });

            res.on('end', function() {
                var jsonObj = JSON.parse(body);
                var price = parseFloat(jsonObj[0].price);

                total += price;

                MongoClient.connect(dbUrl, function(err, db) {
                    if (err)
                        throw err;
                    var dbo = db.db("crypto");
                    dbo.collection("tick").insertOne(jsonObj[0],
                            function(err, res) {
                                if (err)
                                    throw err;
                                db.close();

                            });
                });


                callback(price);
            });



        }).on('error', function(e) {
        console.log("Got an error: ", e);
    });

};


run();

callback that is passed to an iteratee ( httpGet ) is used incorrectly. 传递给iteratee( httpGet )的callback使用不正确。 The first argument ( price ) is considered an error. 第一个参数( price )被认为是错误。 From the docs : 文档

If iteratee passes an error to its callback, the main callback (for the map function) is immediately called with the error. 如果iteratee将错误传递给其回调,则立即使用错误调用主callback (用于map函数)。

So 所以

callback(price);

should rather be 应该是

callback(null, price);

So async does not halt after the first iteration. 因此, async不会在第一次迭代后停止。

I believe there are two separate problems here: 我相信这里有两个独立的问题:

  1. As you may know, we cannot use return statements in asynchronous code like we would in synchronous code, which is why we use callbacks instead. 您可能知道,我们不能像异步代码那样在异步代码中使用return语句,这就是为什么我们使用回调的原因。 Node-style callbacks are on the form function (err, result) {} , where the first parameter is the error (if any) and the second the result of the function (the return value). 节点样式的回调在表单function (err, result) {} ,其中第一个参数是错误(如果有),第二个参数是函数的结果(返回值)。 According to the docs , Async.map(coll, iteratee, callback) will stop the execution if the iteratee passes an error to its callback. 根据文档 ,如果iteratee将错误传递给其回调,则Async.map(coll, iteratee, callback)将停止执行。

    As your iteratee -function is calling its callback as such: callback(price) , you're effectively stopping execution, as price is passed as the error parameter. 当您的iteratee像这样调用其回调: callback(price) ,由于price作为error参数传递了,您实际上正在停止执行。 What you want to do to "return" the price variable, is to call the callback as so: callback(null, price) 要“返回” price变量,您要做的是这样调用回调: callback(null, price)

  2. Typically, map -functions are used for 通常,将map函数用于

    appl[ying] a given function to each element of a list, returning a list of results in the same order. 将给定函数应用于列表的每个元素,以相同顺序返回结果列表。

    The map function of the async library does the same, IE: iterates through an array and returns an array of the resulting items, just like the normal map (below) method does. 异步库的map函数也做同样的事情,即IE:遍历一个数组并返回结果项的数组,就像普通的map方法(下面)一样。

    [1, 2, 3].map(function (nbr) { return nbr*2 }) // returns [2, 4, 6]

    The result parameter of your callback (IE, the third parameter to async.map) will be called with an array of prices, and not the summed value of the prices. callback的结果参数(IE,async.map的第三个参数)将使用价格数组而不是价格的总和来调用。

    async.map(tokens, httpGet, function (error, total) { console.log(error); // prints undefined (unless there was an error) console.log(total); // prints an array of prices });

For summing the values, I would recommend the reduce function, or simply sum the values returned as a result. 为了对这些值求和,我建议使用reduce函数,或者简单地对作为结果返回的值求和。

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

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