Как повторить то же обещание в NodeJS с вводом массива, пока оно не разрешится или массив не закончится?

#node.js

Вопрос:

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

Мой вопрос: как связать повторяющееся одно и то же обещание (каждый раз по другому URL-адресу) с возможностью разорвать цепочку, как только будет найден рабочий URL-адрес?

Ответ №1:

В то время как рекурсивная функция, возвращающая обещание, была бы достаточно простой…

 const getWorkingAudio = (i = 0) => {
  if (i === urls.length) {
    throw new Error('All URLs bad');
  }
  return fetch(urls[i])
    .then(validateHeaders)
    .catch((error) => {
      return getWorkingAudio(i   1);
    });
};
getWorkingAudio()
  .then(handleSuccess)
  .catch(handleError);
 

Это довольно плохой знак, если у вас часто так много URL — адресов, которые могут быть плохими из-за нагрузки на сервер-лучше исправить/улучшить сервер, чем заставлять разработчиков работать над глупыми обходными путями, подобными этому.

Ответ №2:

🤔 🤔 не могли бы вы добавить немного больше контекста ?

  async function checkLinks (links) {
    for (const link of links) {
        try {
             const content = await your checkingThingy()
            // If we are here it means isValid has your BitTorrent or so

             return content
         }  catch (e){}
     }

     // Not found
}
 

Это может вам помочь, но если у вас возникнут какие-либо проблемы, убедитесь, что у вас есть соответствующие плагины babel для обработки

Ответ №3:

Мне удалось заставить его работать следующим образом:

 function audioPicker(audioUrlArray, i){
    return new Promise((resolve, reject) =>{
        audioUrlCheck(audioUrlArray[i])
            .then(isAvailable =>{
                if(isAvailable) resolve(audioUrlArray[i])
                else if (i 1 < audioUrlArray.length){
                    audioPicker(audioUrlArray, i 1)
                    .then(pick => resolve(pick))
                    .catch(e => reject(e))
                } else reject ('All audio files are not available.')
            })
            .catch(e => log("AuidoPicker Error: ", e)) // Don't reject here
    })
}
    
    
function audioUrlCheck(url){
    return new Promise((resolve, reject) =>{
        axios.head(url) // Using axios as "fetch" is not built-in in NodeJS
        .then(r =>{
            log('Fetched audio file URL headers.')
            if(r.headers['content-type'] == 'audio/mpeg') resolve(true)
            else resolve(false)
        })
        .catch(e => resolve(false)) // No reject if Url request failed
    })
}

audioPicker (urlArray, 0)
    .then(pick => resolve(pick))
    .catch(e => reject(e))