Улавливайте несколько вложенных ошибок асинхронных функций в одном блоке улавливания

#node.js

Вопрос:

Приведенный ниже код является примером того, что может произойти во время разработки.

С текущим кодом внешняя функция может выдать ошибку, но в этом случае этого не произойдет. Однако вложенная функция выдаст ошибку (для примера). Как только он выдает ошибку, она не может быть поймана, так как это асинхронная функция.

 Bungie.Get('/Platform/Destiny2/Manifest/').then((ResponseText)=>{

    //Async function that WILL throw an error 
    Bungie.Get('/Platform/Destiny2/Mnifest/').then((ResponseText)=>{
        console.log('Success')
    })

}).catch((error)=>{
    
    //Catch all errors from either the main function or the nested function
    doSomethingWithError(error)
});
 

Я хочу, чтобы внешняя функция most перехватывала все ошибки асинхронных функций, но с этим кодом я не могу. Я пытался дождаться вложенной функции, но могут быть определенные обстоятельства, при которых будет быстрее не ждать функцию. Я также попытался включить a .catch() в каждую вложенную функцию, но для этого потребуется a .catch() для каждой функции, которая будет обрабатывать ошибку таким же образом, например doSomethingWithError() .

Ответ №1:

вам нужно только вернуть внутреннюю функцию во внешнюю функцию. см. Пример ниже:

 const foo = new Promise((resolve,reject) =>{
    setTimeout(() => resolve('foo'), 1000);
});

foo.then((res)=>{
    console.log(res)
    return new Promise((resolve,reject)=>{
        setTimeout(() => reject("bar fail"), 1000);
    })
}).catch((e)=>{
  // your own logic
  console.error(e)
}); 

это называется цепочкой обещаний. смотрите этот пост для получения дополнительной информации https://javascript.info/promise-chaining

если у вас есть несколько обещаний, вы можете сделать что-то вроде:

 const foo1 = new Promise((resolve,reject) =>{
        setTimeout(() => resolve('foo1'), 1000);
});
const foo2 = new Promise((resolve,reject) =>{
        setTimeout(() => resolve('foo2'), 2000);
});
const foo3 = new Promise((resolve,reject) =>{
        setTimeout(() => reject('foo3'), 3000);
});
const bar = new Promise((resolve,reject) =>{
        setTimeout(() => resolve('bar'), 4000);
});

foo1
.then((res)=>{
  console.log(res)
  return foo2
})
.then((res)=>{
  console.log(res)
  return foo3 // throws the error
})
.then((res)=>{
  console.log(res)
  return bar
})
.catch((e)=>{
  // every error will be cached here
  console.error(e)
}); 

Ответ №2:

Я бы хотел использовать async / await, если у вас нет особых причин, так как это позволяет избежать callback hell и делает ваш код проще и без ошибок.

 try {
  const response1 = await Bungie.Get('/Platform/Destiny2/Manifest/');
  const response2 = await Bungie.Get('/Platform/Destiny2/Mnifest/');
  console.log('Success');

} catch (error) {
  doSomethingWithError(error);
}
 

Представьте, что каждый вызов Bungie занимает 250 миллисекунд. Пока это происходит, NodeJS будет продолжать выполнять другой код через свой цикл событий — например, запросы от других клиентов. Ожидание — это не то же самое, что зависание приложения.

Аналогично, этот тип кода используется во многих браузерах или мобильных приложениях, и они остаются отзывчивыми для конечного пользователя во время ввода-вывода. В наши дни я использую модель программирования асинхронного ожидания на всех языках (Javascript, Java, C#, Swift и т.д.).

Ответ №3:

Попробуй это:

 let getMultiple = function(callback, ... keys){
    let result = [];
    let ctr = keys.length;
    for(let i=0;i<ctr;i  )
        result.push(0);
    let ctr2 = 0;
    keys.forEach(function(key){
      let ctr3=ctr2  ;
      try{
        Bungie.Get(key, function(data){
            result[ctr3] = data;
            ctr--;
            if(ctr==0)
            {
                callback(result);
            }
        });
         }  catch(err) { 
             result[ctr3]=err.message;
             ctr--;
            if(ctr==0)
            {
                callback(result);
            }
      }
    });
};
 

Это должно получить все ваши запросы на данные и заменить соответствующие данные сообщением об ошибке, если это произойдет.

     getMultiple(function(results){ 
          console.log(results);
     },  string1, string2, string3);
 

Если ошибка возникает из-за запроса одного и того же дважды асинхронно, вы можете добавить слой асинхронного кэширования перед этим запросом.