#javascript #api #asynchronous #foreach #synchronous
Вопрос:
Итак, чтобы не утомлять никого предысторией, мне нужно получить доступ к данным из нескольких API, чтобы запустить мой скрипт. Все данные должны быть загружены до того, как я выполню скрипт, что мне обычно удобно делать: я просто объявляю некоторые запросы на выборку, пишу Promise.all, затем продолжаю работу с функцией.
ОДНАКО я столкнулся с чем-то вроде путаницы с определенным API, который ограничивает количество результатов, которые я могу извлечь из одного запроса, до 100, и мне нужно запросить все результаты. Я не думал, что это имеет большое значение, поскольку я решил, что могу просто сделать пару дополнительных запросов, добавив «amp;page= X» в конец запроса.
Таким образом, план состоит в том, чтобы запросить общее количество страниц из API, а затем передать это в цикл for, чтобы отправить несколько запросов на выборку в массив обещаний (т. е. link://to/api/dataamp;page = 1, link://to/api/dataamp;page = 2 и т. Д.). Однако, когда я действительно пытаюсь создать этот массив с помощью цикла for, массив возвращается пустым. Вот моя работа:
const dataUrlNoPage = 'link/to/api/dataamp;page=';
const totalPages = 3; //usually pulled via a function, but just using a static # for now
let apiRequestLoop = function(inp) {
return new Promise(function(resolve){
let promiseArray = [];
for (let i = 1; i <= inp; i ) {
let dataUrlLoop = dataUrlNoPage i;
fetch(dataUrlLoop).then(function(response){
promiseArray.push(response.json());
})
}
resolve(promiseArray);
})
}
let finalPromiseArray = apiRequestLoop(totalPages).then(result => {
let requestArray = [apiRequest1,apiRequest2];
//requestArray contains earlier fetch promises
result.forEach(foo => {
requestArray.push(foo);
}
);
return requestArray;
});
Итак, что меня сбивает с толку, так это действительно цикл и то, как он не возвращает массив обещаний. Когда я смотрю на него в консоли, он отображается как пустой массив, но я могу развернуть его и увидеть обещания, которые я ожидал. Я вижу ответ «Значение ниже было оценено только что». Однако, независимо от того, сколько обещаний или .thens я пишу, массив фактически никогда не заполняется во время выполнения.
Что происходит? Могу ли я не генерировать обещания выборки через цикл for?
(Кроме того, чтобы немного сократить эту строку вопросов, да, API, к которому я пытаюсь получить доступ, — это WordPress. Оглядываясь вокруг, большинство людей предлагают создать пользовательскую конечную точку, но давайте предположим, что для целей этого проекта мне запрещено это делать.)
Ответ №1:
Здесь у вас есть несколько проблем.
Во-первых, у вас есть функция, предоставленная new Promise
самой себе, содержащая создания обещаний. Не делайте этого! Это определенный антишаблон, который не поддерживает чистоту вашего кода.
Второй — это базовый бит кода:
let promiseArray = [];
for (let i = 1; i <= inp; i ) {
let dataUrlLoop = dataUrlNoPage i;
fetch(dataUrlLoop).then(function(response){
promiseArray.push(response.json());
})
}
resolve(promiseArray);
Это говорит:
- создайте пустой массив
- перебирайте другой массив, выполняя HTTP-запросы
- разрешите свое обещание с помощью пустого массива
- когда HTTP-запросы будут завершены, добавьте их в массив
Четвертый шаг всегда будет следовать за третьим шагом.
Итак, вам нужно добавлять обещания в свой массив по мере продвижения, и общее обещание будет выполнено, когда все они будут выполнены.
let apiRequestLoop = function(inp) {
let promiseArray = [];
for (let i = 1; i <= inp; i ) {
let dataUrlLoop = dataUrlNoPage i;
promiseArray.push(fetch(dataUrlLoop).then(function(response) {
return response.json();
}));
}
return Promise.all(promiseArray);
}
или с помощью функции со стрелкой для очистки:
let apiRequestLoop = function(inp) {
let promiseArray = [];
for (let i = 1; i <= inp; i ) {
let dataUrlLoop = dataUrlNoPage i;
promiseArray.push(fetch(dataUrlLoop).then(response => response.json()));
}
return Promise.all(promiseArray);
}
Комментарии:
1. Спасибо! Очень ценю, что вы рассказали мне об этом. Рефакторинг был приятным бонусом.
Ответ №2:
Несколько моментов:
- вы хотите фактически поместить сами обещания в массив, а не отправлять в массив в
.then()
цепочке с обещанием. - вероятно, вы хотите пропустить создание нового обещания в своей функции. Просто получите массив всех обещаний из вашего цикла, затем верните a
Promise.all
в массив.
Вот так:
let apiRequestLoop = function(inp) {
let promiseArray = [];
for (let i = 1; i <= inp; i ) {
let dataUrlLoop = dataUrlNoPage i;
promiseArray.push(fetch(dataUrlLoop))
}
return Promise.all(promiseArray);
}
В вашем последнем .then
заявлении в finalPromiseArray вашим результатом будет массив результатов всех обещаний. вот так [response1, response2, response3, ...]
Смотрите Обещание.вся документация для получения более подробной информации.