Arrays 给bluebird一个数组,调用API,然后将结果集成到单个JSON输出中 序言

Arrays 给bluebird一个数组,调用API,然后将结果集成到单个JSON输出中 序言,arrays,json,node.js,promise,bluebird,Arrays,Json,Node.js,Promise,Bluebird,我有一个想法:如果我通过将对象串在一起作为微服务来减少重复的数据结构,那么我为什么不使用sail、nodejs和api调用呢。这就是一切开始的地方 问题定义 如何向函数发送动态数组,向另一个微服务执行未知数量的API调用,然后将返回的值合并到单个对象中进行处理 旅程 我找到了关于q或蓝鸟的资料 我有一个函数(在sails中)可以返回JSON数组中的用户电子邮件地址列表 getUserInfo: function(opt, callback){ var https = require('h

我有一个想法:如果我通过将对象串在一起作为微服务来减少重复的数据结构,那么我为什么不使用sail、nodejs和api调用呢。这就是一切开始的地方

问题定义 如何向函数发送动态数组,向另一个微服务执行未知数量的API调用,然后将返回的值合并到单个对象中进行处理

旅程 我找到了关于q或蓝鸟的资料

我有一个函数(在sails中)可以返回JSON数组中的用户电子邮件地址列表

getUserInfo: function(opt, callback){
    var https = require('https');
    var options = {
        hostname: opt.hostname || 'as.net.au',
        port: opt.port || 443,
        path: opt.path || '/developers',
        method: opt.method || 'GET',
        headers: opt.headers || {'Authorization': 'Basic ' + 'ThuperThecretKey'}
    }

    var req = https.request(options, function(res) {
        var data = '';
        res.setEncoding('utf8');
        res.on('data', function(chunk) {
            //console.log('BODY: ' + chunk); //oh so chunky
            data += chunk;
        });

        res.on('end', function() {
            //console.log(data)
            callback(null, data)
        })
    })

    req.on('error', function(e) {
        console.log('problem with request: ' + e.message)
        callback(e) //error
    })

    req.end()
}
它返回一组JSON数组中的电子邮件地址:

['dev1@thisplace.com','dev2@thisplace.com','dev3@someotherplace.com'] 
我将其粘贴到一个名为“devs”的json对象中

现在我想将这个数组传递给一个函数,让它为每个开发人员执行一个API调用,并将结果添加到json对象或新对象中。我假设一个新的,因为devs是一个数组,而不是一个完整的对象

互联网上的共识似乎是使用蓝鸟,但我正在努力解决我认为每个人都在努力解决的问题,什么变量被命名为什么,哪个变量得到更新,如何将内容加载到变量中,它去了哪里,等等,我的头很痛。有些东西进入入口,我不确定是否应该进入

所以我请求帮助。有没有人举一个例子来说明异步执行这些操作然后解析结果的最佳方法

我已经看到了一个很好的异步调用循环进入我的API(如下所示),但是如何传入并读取最后一个then函数中的变量呢

它记录了“为……履行承诺”dev1@thisplace.com.....等等” 然后“devs”对象为空,而“dev”对象为预期的对象(每个电子邮件地址)

但是如何将API调用的输出传递回调用json(或新json)呢?它如何维护和异步更新对象? 我假设在错误之后有东西进入了else(潜在占位符编号1)

比如:

promise.map(devs, function(dev) {
  console.log('executing a promise for ' + dev)
  MyCont.getUserInfo({'path': '/developers' + dev}, function (err,devs) {
    if (err) {
      console.log(err)
    } else {
      console.log ('devs: ' + devs)
      console.log('dev: ' + dev)
      //Potential placeholder number 1 -Some here that loads the returned value to the passed in or new array?
    }   
  })
}).then(function() {
    //Or maybe it goes here?
    console.log("done");
});

你提到了第一个显而易见的解决方案,使用蓝鸟地图。第一件事是在任何地方使用承诺:

// make this a Promise
getUserInfo: function(opt) {
    // your new best friend for issuing http requests without callbacks
    var request = require('request-promise');

    // the options have to change a little
    var options = {
        uri: 'https://'
               + opt.hostname || 'as.net.au' + ':'
               + opt.port || 443
               + opt.path || '/developers',
        method: opt.method || 'GET',
        headers: opt.headers || {'Authorization': 'Basic ' + 'ThuperThecretKey'}
    }

    // much shorter, right?
    return request(options);
}

devs.map(function(dev) {
    console.log('executing a promise for ' + dev)
    return MyCont.getUserInfo({'path': '/developers' + dev});
}).then(function(results) {
    // your results are here, in order
    console.log(results);
});

在阅读了所有这些之后,我假设你的问题是:

如何使用一组异步函数调用的结果来解析现有承诺

首先,从最外层承诺中的函数开始:

var processEmailAddressList = function (addresses) {
    // This is inside a promise.
    // It will return when all addresses have been processed.
    return Promise.map(addresses, processSingleAddress);
};

var processSingleAddress = function (address) {
    // How you implement this is up to you -- and up to whatever
    // promise library you are using. return a promise that resolves
    // to the value you want
};
这里,我们使用的是
map
,但是我们可以使用
reduce
map
reduce
之间有一些非常重要的性能特征(见下文),但我现在将忽略这些。您需要知道的是,您正在返回一个承诺,当回调处理了
地址中的所有项目时,
processSingleAddress
,该承诺将
解决
拒绝

问题是如何编写
processSingleAddress

如果您能够以一种已经使用承诺的方式处理单个地址,那么它就很简单了。也许你正在使用一个已经准备好的库。在这种情况下,您只需直接调用该函数

var processSingleAddress = function (address) {
    return addressProcessorWithPromise(address);
};
但是,如果你不能用承诺来处理你的列表项,你需要找到一种方法,用你自己创造的承诺来实现。例如,在这里,我假设您正在对
getDataFromAsyncProcess()
进行异步调用,并且该函数接受单个地址和节点样式的回调

var processSingleAddress = function (address) {
    // input is `sample@example.com`
    return new Promise(function (resolve, reject) {
        getDataFromAsyncProcess(address, function (err, data) {
            if (err) reject(err);

            // example output is {address: 'sample@example.com', status: 'logged in'}
            resolve(data);
        });
    });
};
在这一点上,您应该预期事情会像这样运行:

var addresses = ['sample1@example.com', 'sample2@example.com']
processEmailAddressList(addresses)
.then(function (list) {
    // see below for the value of `list`
})
.catch(function (err) {
    console.error(err);
});
[
    {address: 'sample1@example.com', status: 'logged in'},
    {address: 'samples@example.com', status: 'logged in'},
]
之后的
中,列表现在应该如下所示:

var addresses = ['sample1@example.com', 'sample2@example.com']
processEmailAddressList(addresses)
.then(function (list) {
    // see below for the value of `list`
})
.catch(function (err) {
    console.error(err);
});
[
    {address: 'sample1@example.com', status: 'logged in'},
    {address: 'samples@example.com', status: 'logged in'},
]
我知道这看起来可能会与正在进行的间接寻址(函数中的函数)数量混淆,但欢迎使用JS。你越习惯于使用承诺,它就越容易实现

最后要特别注意的是
map
reduce
(或任何其他promise库迭代器)的工作方式。如果您有,5个地址,并且处理成本不太高,这一点也不重要,但是如果您有成百上千的事情要处理,或者处理器成本很高(数据库调用、网络请求、内存消耗等),如果所有这些地址都被并行处理(一次处理),那么最终可能会占用大量内存并杀死数据库。如果这是一个因素,您应该尝试使用迭代器一次只做一件事。有关详细信息,请咨询您的库API


最后一点:请尽量让你的问题简单。这是不必要的冗长。

哇,谢谢你,这是一个令人惊讶的简短回答。这正是我所需要的。谢谢你花时间如此详细地回答这个问题。它的信息量很大。(保持简短)这个问题是最有趣的(+1用于搔痒有趣的骨头),但我们真的不希望在这里写这样的问题(-1用于随后的编辑工作)。谢谢