繁体   English   中英

当API返回值时,如何使用JS Promises继续向API请求?

[英]How Do You Use JS Promises To Keep Requesting From API While The API Returns A Value?

我试图在API继续返回的同时继续从API请求。 我正在使用LaunchLibrary API( https://launchlibrary.net/docs/1.3/api.html ),并且试图从上个月请求启动。

该API总共返回15个结果,但仅显示前10个结果。要获取下五个结果,请将请求传递给偏移量并再次查询(“&offset = 10”),这将为您提供下五个结果。

我想做的是继续从API请求,同时传递偏移量,直到从API返回的计数为零为止。 我正在尝试使用javascript Promises完成此操作,但遇到了一些麻烦。

这是我简洁的“ app.js”节点文件的样子:

app.get("/recent", function(req, res){

    var past_launches = [];
    var offset = 0;
    var count_return = 0;

    var endDate = moment().subtract(1, "days");
    var startDate = moment().subtract(1, "months").subtract(1, "days");

    do {
        var url = "https://launchlibrary.net/1.3/launch?startdate="+startDate.format("YYYY-MM-DD")+"&enddate="+endDate.format("YYYY-MM-DD")+"&offset="+offset+"&mode=verbose";
        var past_launch_promise = new Promise(function(resolve, reject) {
           request(url, function(err, response, body) {
               if(!err && response.statusCode == 200) {
                   var data = JSON.parse(body);
                   resolve(data);
               } else {
                   reject(Error(err));
               }
           });
        }).then(function(result) {
            count_return = result.count;
            offset = count_return;
            past_launches.concat(result.launches);
        },      function(err) {
            console.log(err);
        });
    } while(count_return >= 10);

    res.render("recent",{data:promises, embed:embed, status:status});  
});

我知道问题出在哪里:由于请求是异步的,它将在实际返回之前到达while,并且由于count_return最初为0,所以它会在返回任何内容之前停止。 我以为使用诺言和.then()函数可以强制循环等待,但这显然是不正确的。

这是我正在使用的查询( https://launchlibrary.net/1.3/launch?startdate=2018-01-11&enddate=2018-02-10&mode=verbose )。 通过添加“&offset = 10”,您可以获取启动的下一页。 解决此问题的有效方法是什么。

一种方法是使用递归(通常不建议使用JavaScript中的无界或大循环,因为它们可能导致...等待它...堆栈溢出错误🤣)。

const moment = require('moment');
const request = require('request-promise-native');

function getLaunches(startDate = moment().subtract(1, 'months').subtract(1, 'days'), endDate = moment(startDate).add(1, "months"), offset = 0, launches = []) {
  const url = `https://launchlibrary.net/1.3/launch?startdate=${moment(startDate).format('YYYY-MM-DD')}&enddate=${moment(endDate).format('YYYY-MM-DD')}&offset=${offset}&mode=verbose`;

  return request.get({
    uri: url,
    json: true
  }).then((response) => {
    const total = response.total;
    launches.push(...response.launches);

    if (launches.length < total) {
      const nextOffset = offset + response.count;
      return getLaunches(startDate, endDate, nextOffset, launches);
    }

    return launches;
  });
}

getLaunches().then((launches) => console.log({
  total: launches.length,
  launches
}));

一种替代方法是使用异步 / 等待 (在节点8+中受支持)。 应当注意,这些仍然是实验性功能,但是此答案是为了说明它们如何使异步代码更像示例中的同步代码那样读取。

const moment = require('moment');
const request = require('request-promise-native');

async function getLaunches(startDate = moment().subtract(1, 'months').subtract(1, 'days'), endDate = moment(startDate).add(1, "months"), offset = 0) {
  let total = 0;
  const launches = [];

  do {
    const url = `https://launchlibrary.net/1.3/launch?startdate=${moment(startDate).format('YYYY-MM-DD')}&enddate=${moment(endDate).format('YYYY-MM-DD')}&offset=${offset}&mode=verbose`;
    const response = await request.get({
      uri: url,
      json: true
    });

    total = response.total;
    offset += response.count;
    launches.push(...response.launches);
  } while (launches.length < total);

  return launches;
}

getLaunches().then((launches) => console.log({
  total: launches.length,
  launches
}));

您应该能够通过一些应许池编排来实现此目标,而您可以通过诸如es6-promise-pool之类的东西免费获得。 下面是一个示例,该如何做:

const PromisePool = require('es6-promise-pool')

let count_return = -1;

var promiseProducer = function () {
    if (count_return === -1 || count_return >= 10) {
        var past_launch_promise = new Promise(function(resolve, reject) {
            request(url, function(err, response, body) {
                ...
            });
         }).then(function(result) {
             count_return = result.count;
             ...
         },  function(err) {
             ... // you could set count_return to -1 here for an early exit
         });

         return past_launch_promise; // keep going
    }

    return null; // we're done, tell the promise pool to stop now
}

const concurrency = 1; // only 1 concurrent promise as we want "synchronous like" processing

// Create a pool. 
const pool = new PromisePool(promiseProducer, concurrency);

// Start the pool. 
const poolPromise = pool.start();

// Wait for the pool to settle. 
poolPromise.then(function () {
    res.render ...;  
}, function (error) { ... });

暂无
暂无

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

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