Как получить из API синхронно в Node.js?

TL; DR: как использовать ES6 fetch для загрузки синхронно?

Я пытаюсь написать скрипт в Node для загрузки данных из API, пока их больше не будет для загрузки, например. конечная точка имеет набор данных размером примерно 12000, но предоставляет только 100 на вызов, и мне нужны все данные. Поэтому я решил загрузить его синхронно и останавливаться только тогда, когда возвращенный json окончательно пуст.

// function to make one api GET call
getData = (offset) => {
  return fetch('http://...'+'?start=' + offset)
    .then(...)
}

// make api calls until json is finally empty, 
// indicating that I've downloaded all the data
offset = 0
const results = getData(offset)
while (results.length != 0) {
  // combine results...
  i += 100 // move offset
  results = getData(i)
}

Поскольку я не знаю точно, насколько велики данные и на каком смещении они заканчиваются, то делать ли еще один вызов зависит от последнего.

Приведенный выше код не работает, потому что обещание от getData() не выполняется вовремя для цикла while. На другом языке это было бы нормально, как блоки getData до завершения. Я пробовал awaitgetData, но он должен быть в async (который я не знаю, где разместить, у меня уже есть обещания). Есть ли способ принудительно заблокировать getData(), пока он не будет разрешен?

Функция async также возвращает обещания. поэтому вы можете вызвать getData из другой асинхронной функции и использовать ожидание внутри этой функции

Shorya Vaish 04.08.2018 09:25

Это весь ваш сценарий? Если да, поместите «основной» кодовый блок внутрь async function main() { … } и вызовите его с помощью main().catch(console.error). (Или сделайте это async IIFE)

Bergi 04.08.2018 14:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
1 233
2

Ответы 2

вы можете пометить свою функцию getData () как async

async getData() {
  return fetch('http://...'+'?start=' + offset)
    .then(...)
}

затем await для завершения возвращенного обещания

await const results = getData(offset)

Или вы можете изменить свой код, чтобы обрабатывать логику того, следует ли делать еще один вызов в обратных вызовах обещаний. Что-то вроде

function fetchData(offset) {
  if (offset < 1000) {
    return Promise.resolve([1,2,3].map(i=>offset+i));
  } else {
    return Promise.resolve([]);
  }
}

function needsMoreData(results) {
  return results.length > 0;
}

function fetchNextDataIfNeeded(results, offset) {
  if (needsMoreData(results)) {
    return fetchRemainingData(offset + 100)
     .then(nextResults=>[...results, ...nextResults]);
  }
  return Promise.resolve(results);
}

function fetchRemainingData( offset) {
  return fetchData(offset)
      .then(results=>fetchNextDataIfNeeded(results, offset));
}


function fetchAllData() {
  return fetchRemainingData(0)
   .then(results=>console.info(results));
}

fetchAllData();

См. https://jsfiddle.net/rwycbn5q/1/

Недавно я оказался в похожей ситуации, но некоторые функции невозможно выполнить синхронно. Но вы могли бы сделать что-то вроде этого:

let results=[];

getData(idx)=>{
  fetch("url").then(data=>{
    if (data!= = {}){ //Or some other continuation check
      results.push(data); //Or whatever you want to do with the data
      getData(idx+100);
    }
  })
}

getData(0);

Другие вопросы по теме