Ошибка повторного отображения в обещании catch

88

В учебнике я нашел следующий код:

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

Я немного сбит с толку: вызов catch что-нибудь дает? Мне кажется, что это не имеет никакого эффекта, так как просто выдает ту же ошибку, которая была поймана. Я основываю это на том, как работает обычный try / catch.

Тайлер Дерден
источник
Не могли бы вы дать ссылку на учебник? Может быть, есть дополнительный контекст, который был бы полезен ...
Игорь
@ Игорь Я не могу, это на Pluralsight. Возможно, это просто заполнитель для логики обработки ошибок?
Тайлер Дерден
Это то, что я мог бы предположить, поскольку он не делает ничего, кроме передачи ошибки вызывающей стороне, что также может быть достигнуто, если не иметь уловки для начала.
Игорь
1
@TylerDurden Я подозреваю, что вы правы, говоря, что это заполнитель.
Джаред Смит
@TylerDurden, я бы тоже подумал, что это заполнитель. Может, пытаюсь продемонстрировать, как форматировать / нормализовать ошибки. По сути, обещание-эквивалент try { ... }catch(error){ throw new Error("something went wrong") }. Или показать, что обещания и ошибки совместимы (по крайней мере, так) . Но в текущей реализации это просто глупо. Вы правы, он ничего не делает, и это даже не похоже на ловушку, которую вы добавили бы в ООП, чтобы разрешить перезапись в наследуемом классе. Я бы добавил блок catch, как только он что-то сделает, но не так, не только как заполнитель.
Thomas

Ответы:

124

Нет смысла голым ловить и бросать, как вы показываете. Он не делает ничего полезного, кроме добавления кода и медленного выполнения. Итак, если вы собираетесь выполнить .catch()повторную загрузку, в файле должно быть что-то, что вы хотите сделать, в .catch()противном случае вам следует просто .catch()полностью удалить файл.

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

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});

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


Вот некоторые из полезных причин для ловли и повторного заброса:

  1. Вы хотите зарегистрировать ошибку , но сохранить цепочку обещаний как отклоненную.
  2. Вы хотите превратить ошибку в другую ошибку (часто для упрощения обработки ошибок в конце цепочки). В этом случае вы бы повторно выдали другую ошибку.
  3. Вы хотите выполнить несколько операций, прежде чем цепочка обещаний продолжится (например, закрыть / освободить ресурсы), но вы хотите, чтобы цепочка обещаний оставалась отклоненной.
  4. Вам нужно место для размещения точки останова для отладчика в этой точке цепочки обещаний, если произойдет сбой.

Но простой перехват и повторное выполнение той же ошибки без другого кода в обработчике перехвата не делают ничего полезного для нормального выполнения кода.

jfriend00
источник
На мой взгляд, это не очень хороший пример. При таком подходе легко получить многократную запись в журнал на 1 ошибку. В java вы можете, просто throw new Exception(periousException);я не знаю, поддерживает ли javascript вложенные ошибки, но в любом случае «записать и выбросить» - плохая практика.
Cherry
26
@Cherry - Нельзя сказать, что это вообще плохая практика. Бывают случаи, когда модуль хочет регистрировать свои ошибки по-своему, и это один из способов сделать это. Кроме того, я не рекомендую это, я просто объясняю, что нет причин иметь .catch()и выдавать ту же ошибку внутри catch, если вы не сделаете ЧТО-ТО еще в .catch(). В этом суть этого ответа.
jfriend00
Обычно исключения должны соответствовать уровню абстракции. Совершенно нормально, например, поймать исключение, связанное с базой данных, и выбросить что-то вроде исключения «службы», которое будет обработано вызывающим. Это особенно полезно, когда вы не хотите раскрывать подробности об исключениях низкого уровня
maxTrialfire
3
Еще одна веская причина поймать и (иногда) выбросить - это обработать конкретную ошибку, но повторно выбросить все остальное.
Джаспер
2
@SimonZyx - Да, .finally()может быть очень полезно для этого, но иногда ресурсы уже позаботятся о безошибочном пути, поэтому их .catch()все еще можно закрыть. Это действительно зависит от ситуации.
jfriend00
15

Как .then()и .catch()методы возвращают посылы, и если вы выбросить исключение в любом обработчике, возвращаемое обещание отвергаются и исключение будет поймано в следующем отклонить обработчик.

В следующем коде мы генерируем исключение в первом .catch(), которое перехватывается во втором .catch():

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});

Второй .catch()возвращает выполненное обещание,.then() обработчик может быть вызван:

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});

Полезная ссылка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Надеюсь это поможет!

Филипп Султан
источник
4

Если вы catchполностью опустите вызов метода, нет важной разницы .

Единственное, что он добавляет, - это дополнительная микрозадача, что на практике означает, что вы заметите отклонение обещания позже, чем в случае обещания, которое не выполняется без catchпредложения.

Следующий фрагмент демонстрирует это:

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );

Обратите внимание, как второе отклонение сообщается раньше первого. Это почти единственная разница.

трико
источник
3

Похоже, ваш вопрос: «Что делает .catch()метод в цепочке обещаний ?»

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw

Оператор throw «остановится (операторы после throw не будут выполнены), и управление будет передано первому блоку catch в стеке вызовов. Если среди вызывающих функций нет блока catch, программа завершится».

В цепочке обещаний .then()метод вернет фрагмент данных определенного типа. Этот возврат фрагмента завершит обещание. Успешный возврат данных завершает обещание. Вы можете думать о .catch()методе таким же образом. .catch()однако будет обрабатывать неудачные попытки получения данных. Оператор throw завершает обещание. Иногда вы увидите, что разработчики используют, .catch((err) => {console.log(err))} что также завершает цепочку обещаний.

Мэтт Фернандес
источник
0

На самом деле вам не нужно повторно бросать его, просто оставьте Promise.catch пустым, иначе он будет рассматривать как un обработать отклонение, а затем заключить код в try catch, и он автоматически поймает ошибку, которая передается вниз.

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}
Айлиан Краспа
источник
0

В цепочке обещаний лучше использовать .catch

ex в функции f2: .then (...). catch (e => reject (e));

  • test1 - с попыткой поймать
  • test2 - без try или .catch
  • test3 - с .catch

function f1() {
    return new Promise((resolve, reject) => {
        throw new Error('test');
    });
}

function f2() {
    return new Promise((resolve, reject) => {
        f1().then(value => {
            console.log('f1 ok ???');
        }).catch(e => reject(e));
    });
}

function test1() {
    console.log('test1 - with try catch - look in F12');
    try {
      f2().then(() => { // Uncaught (in promise) Error: test
        console.log('???'); });
    } catch (e) {
      console.log('this error dont catched');
    }
}

function test2() {
    console.log('test2 - without try or .catch - look in F12');
    f2(); // Uncaught (in promise) Error: test
}

function test3() {
  console.log('test3 - with .catch');
  f2().then(value => {
    console.log('??');
  }).catch(e => {
    console.log(' now its ok, error ', e);
  })
}

setTimeout(() => { test1(); 
  setTimeout(() => { test2(); 
    setTimeout(() => { test3(); 
    }, 100);
  }, 100);
}, 100);

Вагнер Перейра
источник