Синхронные / последовательные вызовы REST в цикле - PullRequest
0 голосов
/ 07 апреля 2019

Я пытаюсь вызвать REST API в цикле «for», однако результаты не соответствуют ожиданиям.

Я пытался обернуть все в обещание, но порядок операций все еще выключен, выполняя его асинхронно, а не синхронно.

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 Ответ

1 голос
/ 07 апреля 2019

Проблема в том, что функция обратного вызова, которую вы передали функции https.get(), выполняется асинхронно и что функция getLocation не ждет, пока эта часть не разрешится.

Таким образом, вы можете просто обернуть вызов https.get() и разархивировать часть в обещание, дождаться его разрешения и затем выполнить аксиос-часть.

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);
    })
}
...