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 function main() { … } и вызовите его с помощью main().catch(console.error). (Или сделайте это async IIFE)



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


вы можете пометить свою функцию 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();
Недавно я оказался в похожей ситуации, но некоторые функции невозможно выполнить синхронно. Но вы могли бы сделать что-то вроде этого:
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);
Функция async также возвращает обещания. поэтому вы можете вызвать getData из другой асинхронной функции и использовать ожидание внутри этой функции