循环中的同步/顺序REST调用

时间:2019-04-07 10:06:00

标签: node.js rest promise async-await

我试图在“ for”循环中调用REST API,但是结果不是我所期望的。

我尝试将所有内容包装在一个promise中,但是操作顺序仍然不正确,不是异步执行,而是同步执行。

var https = require('https');
var zlib = require("zlib");
var axios = require('axios');
const cheerio = require('cheerio');

var page = 1;
var hasMore = "true";

function delay() {
  return new Promise(resolve => setTimeout(resolve, 300));
}

async function getLocation(page) {
  // notice that we can await a function
  // that returns a promise
  await delay();
  var apiUrl = 'https://my.api.com/search/advanced?page=' + page +
      '&pagesize=5';

  https.get(apiUrl, function(response) {
    console.log("headers: ", response.headers);
    console.log(response.statusCode)

    if (response.statusCode == 200) {
      var gunzip = zlib.createGunzip();
      var jsonString = '';
      response.pipe(gunzip);

      gunzip.on('data', function(chunk) {
        jsonString += chunk;
      });

      gunzip.on('end', function() {
        obj = JSON.parse(jsonString);
        var url = obj.items[0].owner.link;

        axios(url)
          .then(response => {
          const html = response.data;
          const $ = cheerio.load(html);
          //OUTPUT LOCATION
          console.log($('h3.location').text().trim());
        })
          .catch(console.error);

      });

      gunzip.on('error', function(e) {
        console.log(e);
      });
    } else {
      console.log("Error");
    }
  });
}

async function startGetLocation() {
  var page = 1;
  var hasMore = "true";

  do {
    //OUTPUT PAGE NUMBER  
    console.log(page.toString());
    await getLocation(page);
    page = page + 1;
  } while (page < 3);
}

startGetLocation();

基于示例代码,我希望以下内容能够输出:

    1
    New York
    2

但是,它正在输出:

    1
    2
    New York

1 个答案:

答案 0 :(得分:1)

问题在于传递给https.get()函数的回调函数是异步执行的,并且getLocation函数不会等到这一部分解决之后再执行。

因此,您可以简单地将https.get()调用和解压缩部分包装在promise中,等待其解决,然后再进行axios部分。

async function getLocation(page) {
    await delay();
    var apiUrl = 'https://my.api.com/search/advanced?page=' + page +
        '&pagesize=5';

    const fetchAndUnzipPromise = new Promise((resolve, reject) => {
        https.get(apiUrl, function (response) {
            console.log("headers: ", response.headers);
            console.log(response.statusCode)
            if (response.statusCode == 200) {
                var gunzip = zlib.createGunzip();
                var jsonString = '';
                response.pipe(gunzip);
                gunzip.on('data', function (chunk) {
                    jsonString += chunk;
                });
                gunzip.on('end', function () {
                    obj = JSON.parse(jsonString);
                    var url = obj.items[0].owner.link;
                    resolve(url);
                });
                gunzip.on('error', function (e) {
                    reject(e);
                });
            } else {
                reject(new Error("Statuscode not as exepcted"));
            }

        });
    });

    return fetchAndUnzipPromise.then(url => {
        return axios(url)
            .then(response => {
                const html = response.data;
                const $ = cheerio.load(html);
                //OUTPUT LOCATION
                console.log($('h3.location').text().trim()); 
            })
            .catch(console.error);
    })
}