繁体   English   中英

NodeJS承诺:组合多个HTTP请求的正确方法返回

[英]NodeJS Promises: Proper way to combine multiple HTTP requests returns

有一个NodeJS流程可以连接到Web服务获取所谓的Kudos。 这些荣誉从一个人发送到另一个人/或一群人。 我正在尝试做的是创建一条包含以下内容的消息:


从{poster}到{receiver / s}的荣誉

{荣誉消息}


目前,我的程序可以正常工作,以将海报发布给一个接收者。 我正在努力使其与接收者的多个名称一起使用。

问题源于以下事实:返回用户的部分,仅提供用户ID。 因此,我需要拨打另一个电话以获得用户名。 我可以很容易地获得一个用户可以使用的承诺,但是我似乎可以正确地获得多个用户。

包含多个用户的JSON数据如下所示:

 "notes_user": [
  {
    "id": "1060",
    "note_id": "795",
    "user_id": "411"
  },
  {
    "id": "1061",
    "note_id": "795",
    "user_id": "250"
  },
  {
    "id": "1062",
    "note_id": "795",
    "user_id": "321"
  }
],

这是完成大部分工作的函数:

getMaxId返回当前正在处理的最高荣誉的数据库索引,而getKudos仅返回“ kudos”的json数据集。

function promisifiedKudos() {
var maxid;
var newmaxid;

Promise.all([getMaxId(), getKudos()])
    .then(function(results) {
        maxid = results[0];

        var kudos = results[1];
        newmaxid = kudos[0].id;
        return kudos.filter(function(kudo) {
            if (maxid < kudo.id) {
                return kudo;
            }
        })
    })
    .each(function(kudo) {
        return getTribeUserName(kudo);
    })
    .then(function(results) {
        return results.map(function(kudo) {
            var message = "Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n";
            message += "\r\n";
            return message += entities.decode(striptags(kudo.note));
        })
    })
    .each(function(message) {
        return postStatus(message);
    })
    .then(function() {
        var tribehr = db.get('tribehr');
        console.log(new Date().toString() + ":Max ID:" + newmaxid);
        tribehr.update({ endpoint: "kudos" }, { $set: { id: newmaxid } });
    })
    .done(function(errors) {
        console.log("Run Complete!");
        return "Done";
    });
}

辅助函数getTribeUserName()

function getTribeUserName(kudo) {
return new Promise(function(fulfill, reject) {
    var id = kudo.notes_user[0].user_id;
    var options = {
        url: "https://APIURL.com/users/" + id + ".json",
        method: "GET",
        headers: {
            "Authorization": "Basic " + new Buffer("AUTHCODE" + AUTHKEY).toString('base64')
        }
    }
    request.getAsync(options).then(function(response) {
        if (response) {
            var data = JSON.parse(response.body)
            kudo.kudo_receiver_full_name = data.User.full_name;
            fulfill(kudo);
        } else {
            reject("Get Tribe User Name Failed");
        }
    });
});
}

我尝试添加一个帮助器函数,该函数调用如下所示的getTribeUserName():

function getTribeUsers(kudo) {
return new Promise(function(fulfill, reject) {
    kudo.notes_user.map(function(user) {
        //Make calls to a getTribeUserName
    })
});
}

但是结果是,在将完成的消息放在一起时,用户名是不确定的。

关于如何更好地使用Promise的任何指示都将非常有帮助。 这确实是我第一次与他们合作,我希望我朝着正确的方向前进。 我知道我需要添加错误检查功能,但目前我只是想让该流程适用于多个用户。

如果你需要使用作为参数传递一个承诺的结果, resolve功能,那么你可以在抓住它then onFulfilled回调。

如果您需要将在信息链的then方法中获得的某些数据传递给另一个, then只需将其返回并通过随后thenonFulfilled回调对其进行捕获。

object.somePromise().then(function(param){
    var data = someFunction();
    return data;
}).then(function(param){
    //param holds the value of data returned by the previous then
    console.log(param);
});

如果是异步获取多个TribeUserNames的问题,那么您需要以某种方式汇总由多次调用getTribeUserNames()返回的getTribeUserNames()

您可以编写Promise.all(array.map(mapper))但是Bluebird提供了更方便的Promise.map(array, mapper)

蓝鸟的.spread()也方便,对于引用maxidkudos

这是我可以管理的一种简单形式:

function promisifiedKudos() {
    return Promise.all([getMaxId(), getKudos()])
    .spread(function(maxid, kudos) {
        var newmaxid = kudos[0].id;
        // The following line filters (synchronously), adds TribeUserNames (asynchronously), and delivers an array of processed kudos to the next .then().
        return Promise.map(kudos.filter((kudo) => kudo.id > maxid), getTribeUserName)
        .then(function(filteredKudosWithTribeUserNames) { // in practice, shorten arg name to eg `kudos_`
            return Promise.map(filteredKudosWithTribeUserNames, function(kudo) {
                return postStatus("Kudos from " + kudo.poster.full_name + " to " + kudo.kudo_receiver_full_name + "\r\n\r\n" + entities.decode(striptags(kudo.note)));
            });
        })
        .then(function() {
            var tribehr = db.get('tribehr');
            console.log(new Date().toString() + ":Max ID:" + newmaxid);
            return tribehr.update({ endpoint: 'kudos' }, { $set: { 'id': newmaxid } });
        });
    })
    .then(function() {
        console.log('Run Complete!');
    }).catch(function(error) {
        console.log(error);
        throw error;
    });
}

getTribeUserName()需要返回一个getTribeUserName() ,可以这样编写:

function getTribeUserName(kudo) {
    var options = {
        'url': 'https://APIURL.com/users/' + kudo.notes_user[0].user_id + '.json',
        'method': 'GET',
        'headers': {
            'Authorization': 'Basic ' + new Buffer('AUTHCODE' + AUTHKEY).toString('base64')
        }
    }
    return request.getAsync(options).then(function(response) {
//  ^^^^^^
        if(response) {
            kudo.kudo_receiver_full_name = JSON.parse(response.body).User.full_name;
        } else {
            throw new Error(); // to be caught immediately below.
        }
        return kudo;
    }).catch(function(error) { // error resistance
        kudo.kudo_receiver_full_name = 'unknown';
        return kudo;
    });
}

进一步说明:

  • 通过在.spread()回调中嵌套Promise.map(...).then(...).then(...)newmaxid可以通过闭包保持可用,从而避免了使用丑陋的外部newmaxid
  • Promise.map()被用于在假定的第二时间postStatus()是异步的。 如果不是这样,尽管编写的代码可能略有不同,但是代码仍然可以正常工作。

暂无
暂无

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

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