Выполнение запроса на выборку в цикле

Я работаю над приложением, которое возвращает список идентификаторов из первого запроса на выборку. После получения идентификаторов я должен просмотреть идентификаторы и получить подробную информацию о каждом элементе, а затем отобразить его на экране.

  fetch(TOP_STORIES)
  .then(function(response){
    return response.json()
  }).then(function(storyIds){
      // storyIds is [22,33,44,55,66,77,88,99,123,213,342,45456,778,888]
      // is this the best way to fetch all the details of the story
      storyIds.forEach(function(storyId){

        let storyDetailsURL = `https://someurl/v0/item/${storyId}.json?print=pretty`

        fetch(storyDetailsURL)
        .then((response) => response.json())
        .then((story) => {
            displayStory(story)
        })
      })

  })

Мой вопрос в том, что зацикливание лучший способ получить результаты?

ОБНОВЛЕНИЕ: Promise.all вызывает у меня проблемы:

введите здесь описание изображения

ОБНОВЛЕНИЕ: использование Async и ожидания

async function fetchTopHeadlinesAsyncAwait() {

  let response = await fetch(TOP_STORIES)
  let storyIds = await response.json()

  for(let storyId of storyIds) {
    console.log(storyId)
    let storyDetailsURL = `someurl/er/tg/${storyId}.json?print=pretty`
    let response = await fetch(storyDetailsURL)
    let story = await response.json()
    displayStory(story)
  }
}

person john doe    schedule 14.03.2019    source источник
comment
мне это не нравится, потому что он забивает сервер всеми запросами сразу. Обычно лучше запрашивать их по одному. Для этого я определяю, индексирую и создаю функцию next(), которая извлекает один элемент по идентификатору. next() проверяет индекс, чтобы увидеть, является ли он последним. Если нет, увеличьте индекс и вызовите next(), в противном случае остановитесь и сделайте что-нибудь еще. Не забудьте вызвать next() вручную один раз в нижней части содержащего контекста...   -  person dandavis    schedule 14.03.2019
comment
кстати, если вы переключитесь на использование кода стиля async / await вместо Promise.then, он очистит красиво и удобнее в использовании. Однако обещания — это здорово. Кроме того, чтобы получать детали истории только тогда, когда это необходимо, это то, что я бы сделал.   -  person gkelly    schedule 14.03.2019
comment
Можете ли вы попробовать просто удалить строку функции json()?   -  person Bjarne Gerhardt-Pedersen    schedule 14.03.2019
comment
@BjarneGerhardt-Pedersen Если я удалю json(), то как я получу json из ответа?   -  person john doe    schedule 14.03.2019
comment
ааа, асинхронно/ожидание. так чище.   -  person gkelly    schedule 14.03.2019
comment
@johndoe я обновил свой ответ, так что json теперь должен работать с массивом обещаний. .json() не работал, потому что он вызывался для массива ответов.   -  person Bjarne Gerhardt-Pedersen    schedule 15.03.2019


Ответы (2)


Вы можете использовать функциональность Promise.all для получения списка асинхронных действий. Они будут завершены, когда все будут успешными.

Вот пример вашего кода с Promise all, дайте мне знать, как это работает :)

const fetchStories = () => {
  let response = await fetch(TOP_STORIES);
  let storyIds = await response.json();

    let urls = [];
    storyIds.forEach(function(storyId) {
      urls.push(`https://someurl/v0/item/${storyId}.json?print=pretty`);
    });

    Promise.all(
      urls.map(url =>
        fetch(url)
          .then(response => response.json())
          .catch(err => console.error(err))
      )
    ).then(stories => stories.forEach(story => displayStory(story)));
}
person Bjarne Gerhardt-Pedersen    schedule 14.03.2019
comment
Спасибо! В вашем коде, если одно из обещаний терпит неудачу, оно прерывает все или все еще получает те, которые были успешными. - person john doe; 14.03.2019
comment
Привет. Если одно обещание не выполняется, все они не сработают, используя эту технику. - person Bjarne Gerhardt-Pedersen; 14.03.2019
comment
Спасибо! Я не думаю, что хочу этого, поскольку я вытаскиваю новостные статьи, и если одна из них терпит неудачу, я не хочу, чтобы все провалилось. - person john doe; 14.03.2019
comment
вместо этого используйте Promise.any в цикле - person gkelly; 14.03.2019

Этот простой try/catch делает ваш асинхронный код не ломающимся, если одна из историй выдает ошибку. В этом случае я показываю ошибку, используя вашу функцию displayStory, но делайте все, что хотите.

async function fetchTopHeadlinesAsyncAwait() {

  let response = await fetch(TOP_STORIES)
  let storyIds = await response.json()

  for(let storyId of storyIds) {
    console.log(storyId)
    let storyDetailsURL = `someurl/er/tg/${storyId}.json?print=pretty`
    try {
      let response = await fetch(storyDetailsURL)
      let story = await response.json()
      displayStory(story)
    } catch (err) {
      displayStory('An error occurred while fetching this story.');
    }

  }
}
person DoHn    schedule 14.03.2019