【问题标题】:Correct way of populating object with waterfall用瀑布填充对象的正确方法
【发布时间】:2017-10-12 10:53:16
【问题描述】:

我的节点、js 模块中有一个名为 data 的对象:

{
    "item_uuid": "77306c44-4175-4aee-866d-d8df89fa3ii9",
    "accounts": [{
        "accountid": "B15501",
        "quantity": 1
    },
    {
        "accountid": "S20000",
        "quantity": 1
    }]
}

我需要通过将 accountid 传递给 API 来使用国家代码填充帐户中的每个帐户,然后再传递整个数据以进行进一步处理。

所以我在帐户中循环每个帐户并执行以下操作:

data.accounts.forEach(function(account) {

    var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
    request.get(clientAPI, function (err, response, body) {
        if (err) {
            console.log("Unable to get country code for " +
                    account.accountid + " : " + err.message);
        } else {
            var clientData = JSON.parse(body);
            account.country_code = clientData.country
        }
    })
}

// once all accounts have got country code, perform insertion into database
processData(data);

不幸的是,对 clientAPI 的调用是异步的,它不会等待返回结果,因此当数据到达 processData 时,它仍然没有 country_code。

所以我在这里尝试瀑布:

var waterfall = require('async-waterfall');

waterfall([
    function (callback) {
        data.accounts.forEach(function(account) {

            var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
            request.get(clientAPI, function (err, response, body) {
                if (err) {
                    console.log("Unable to get country code for " + account.accountid + " : " + err.message);
                } else {
                    var clientData = JSON.parse(body);
                    account.country_code = clientData.country
                }
            })
        }

        callback(null, data);
    }
], function(err, data){
    processData(data);          
})

可惜还是不行,到了processData(data),还是没有country_code。

我在这里使用瀑布时缺少什么?在 processData(data) 之前,我还能做些什么来填充上面的 country_code?

我必须调用 API 来获取每个帐户的 country_code。

【问题讨论】:

    标签: node.js


    【解决方案1】:

    尝试 Promise(可能还有 node 7.6+ 中的新 await/async 语法),它们会产生更清晰、更合乎逻辑的代码流。

    const Promise = require('bluebird')
    const request = Promise.promisifyAll(require('request'))
    
    function getData(data){
      return Promise.each(data.accounts, function(account){
        const clientAPI = {
          method: 'GET',
          json: true,
          uri: `http://0.0.0.0:3000/${account.accountid}/?fields=country`,
        }
        return request.getAsync(clientAPI).then(function(response){
          if (!response.body.country) throw new Error('No country on '+account.accountid')
          account.country_code = response.body.country
        })
        .catch(function(err){
          console.error('Unable to get country code for '+account.accountid+' : '+err.message, err);
        })
      })
    }
    
    getData(data).then(function(){ processData(data) })
    

    您还可以使用Promise.map 进行一些并发,而不是使用Promise.each,后者是串行的,将等待每个请求完成,然后再进行下一个请求。

    不捕获错误(或重新抛出 err)将导致 Promise 被拒绝而不是被记录,这可能对程序更有用。 Promises 的好处是错误会冒出来,因此您可以在程序/调用开始时以更全局的方式处理错误。

    【讨论】:

    • 谢谢,不幸的是我被旧的 node.js v4 卡住了,我如何在没有 await/async 语法的情况下使用 Promise,而只使用上面的 Promise?
    • 更新为直接承诺。基本上任何有await 的地方都会变成.then()
    • 太棒了,返回 Promise.each 拯救了我的一天!
    【解决方案2】:

    如果您使用 Promise、async/await 或生成器语法,这会更好地实现。

    使用回调,使用计数器变量来跟踪您发送的请求数量,并在调用processData之前等待计数器达到特定值。

    let counter = 0;
    
    data.accounts.forEach(function(account) {
    
    var clientAPI = "http://0.0.0.0:3000/" + account.accountid + "/?fields=country";
    request.get(clientAPI, function (err, response, body) {
        if (err) {
            console.log("Unable to get country code for " +
                    account.accountid + " : " + err.message);
            counter++
        } else {
            var clientData = JSON.parse(body);
            account.country_code = clientData.country
            counter++
        }
    })
    }
    
    // once all accounts have got country code, perform insertion into database
    if (counter === data.accounts.length) processData(data);
    

    【讨论】:

    • 不知道 if (counter === data.accounts.length) 在这里如何工作?
    猜你喜欢
    • 1970-01-01
    • 2015-03-15
    • 2018-03-31
    • 2019-10-22
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2015-05-28
    相关资源
    最近更新 更多