如何循环请求承诺 API 请求调用?

Posted

技术标签:

【中文标题】如何循环请求承诺 API 请求调用?【英文标题】:How to loop request-promise API request call? 【发布时间】:2017-01-23 05:29:44 【问题描述】:

我正在学习 Node.JS,我被介绍到 request-promise 包。我将它用于 API 调用,但我遇到了无法对其应用循环的问题。

这是一个简单的 API 调用示例:

var read_match_id = 
    uri: 'https://api.steampowered.com/IDOTA2Match_570/GetMatchHistory/V001',
    qs: 
        match_id: "123",
        key: 'XXXXXXXX'
    ,
    json: true
;

rp(read_match_id)
.then(function (htmlString) 
    // Process html...
)
.catch(function (err) 
    // Crawling failed...
);

我怎么会有这样的循环:

 var match_details[];
 for (i = 0; i < 5; i++) 
     var read_match_details = 
              uri: 'https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001',
            qs: 
                  key: 'XXXXXXXXX',
                  match_id: match_id[i]
                ,
            json: true // Automatically parses the JSON string in the response 
    ;
    rp(read_match_details)
       .then (function(read_match)
            match_details.push(read_match)//push every result to the array
        ).catch(function(err) 
            console.log('error');
        );
    

我如何知道所有异步请求何时完成?

【问题讨论】:

Promise.all 是你需要了解的内容 @JaromandaX 感谢您的回复... 有时授人以鱼不如授人以渔 @JaromandaX 确实如此.. erm 我可以从下面的答案中问回问题吗?这是处理异步请求的最佳方法吗?还是这只是复杂的? 【参考方案1】:

request-promise 使用 Bluebird 作为 Promise。

简单的解决方案是Promise.all(ps),其中ps 是一组promise。

var ps = [];
for (var i = 0; i < 5; i++) 
    var read_match_details = 
        uri: 'https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001',
        qs: 
            key: 'XXXXXXXXX',
            match_id: match_id[i]
        ,
        json: true // Automatically parses the JSON string in the response 
    ;
    ps.push(rp(read_match_details));


Promise.all(ps)
    .then((results) => 
        console.log(results); // Result of all resolve as an array
    ).catch(err => console.log(err));  // First rejected promise

这样做的唯一缺点是,这将在任何承诺被拒绝后立即进入 catch 块。 4/5 解决了,没关系,1 个被拒绝就扔了。

另一种方法是使用 Bluebird 的检查 (refer this)。我们会将所有 Promise 映射到它们的反射,我们可以对每个 Promise 进行 if/else 分析,并且即使有任何 Promise 被拒绝,它也会起作用

// After loop
ps = ps.map((promise) => promise.reflect()); 

Promise.all(ps)
    .each(pInspection => 
        if (pInspection.isFulfilled()) 
            match_details.push(pInspection.value())
         else 
            console.log(pInspection.reason());
        
    )
    .then(() => callback(match_details)); // Or however you want to proceed

希望这能解决您的问题。

【讨论】:

感谢您的回复.. 我想我需要时间来消化,因为我只是一个初学者.. 我想问这​​是否是处理异步请求的最佳方法?或者这只是复杂的 TBH,几个月前我刚刚开始使用 NodeJS。通常在这种情况下,使用批量 API,您可以通过一个请求快速获取所有此类数据。但由于这些 API 是公开的,我认为不会有任何可用的批量 API。这种方法没有任何问题,(其他用户会另外指出)。只是一件事,不要只是复制粘贴,在使用之前要遍历每个函数的定义。 node 的异步特性,理解起来有点不同,但是一旦你理解了它,你就会大吃一惊,你就会释放出 NodeJS 的全部潜力。 @AshwaniAgarwal 在您的第一个示例中,rp() 函数是什么? @parsley72 request-promise 库实例

以上是关于如何循环请求承诺 API 请求调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何从循环中收集Facebook API请求的响应?

如何构造循环API调用以使JSON结果可用?

在承诺完成之前退出 forEach

如何在 while 循环内更新 api 调用?

循环使用可变 URL 的 api 获取请求

编写Twisted Client以向多个API调用发送循环GET请求并记录响应