2015-10-30 7 views
129

Я прочитал несколько статей по этому вопросу, но мне все еще не ясно, есть ли разница между Promise.reject и ошибкой. Например,JavaScript Promises - отклонение против броска

Использование Promise.reject

return asyncIsPermitted() 
    .then(function(result) { 
     if (result === true) { 
      return true; 
     } 
     else { 
      return Promise.reject(new PermissionDenied()); 
     } 
    }); 

Использование броска

return asyncIsPermitted() 
    .then(function(result) { 
     if (result === true) { 
      return true; 
     } 
     else { 
      throw new PermissionDenied(); 
     } 
    }); 

Я предпочитаю использовать throw просто потому, что он короче, но было интересно, если есть какие-либо преимущество одного над другим.

+1

Оба метода производят точно такую ​​же реакцию. Обработчик '.then()' ловит заброшенное исключение и автоматически превращает его в отклоненное обещание. Поскольку я читал, что заброшенные исключения не особенно быстро выполняются, я бы предположил, что возврат отклоненного обещания может быть немного быстрее для выполнения, но вам нужно будет разработать тест в нескольких современных браузерах, если это важно знать. Я лично использую 'throw', потому что мне нравится читаемость. – jfriend00

+0

@webduvet не с обещаниями - они предназначены для работы с броском. – joews

+5

Один недостаток «бросить» заключается в том, что это не приведет к отвергнутому обещанию, если оно было выброшено из асинхронного обратного вызова, например, setTimeout. http://jsfiddle.net/m07van33/ @Blondie, ваш ответ был верным. –

ответ

116

Нет преимущества использования одного и другого, но существует конкретный случай, когда throw не будет работать. Однако эти случаи могут быть исправлены.

Каждый раз, когда вы находитесь в обратном вызове с обещанием, вы можете использовать throw. Однако, если вы используете какой-либо другой асинхронный обратный вызов, вы должны использовать reject.

Например,

new Promise(function() { 
 
    setTimeout(function() { 
 
    throw 'or nah'; 
 
    // return Promise.reject('or nah'); also won't work 
 
    }, 1000); 
 
}).catch(function(e) { 
 
    console.log(e); // doesn't happen 
 
});

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

function timeout(duration) { // Thanks joews 
 
    return new Promise(function(resolve) { 
 
    setTimeout(resolve, duration); 
 
    }); 
 
} 
 

 
timeout(1000).then(function() { 
 
    throw 'worky!'; 
 
    // return Promise.reject('worky'); also works 
 
}).catch(function(e) { 
 
    console.log(e); // 'worky!' 
 
});

+17

Стоит упомянуть, что места внутри непролонгированного асинхронного обратного вызова, которые нельзя использовать 'throw error', вы также не можете использовать' return Promise.reject (err) ', что и требовалось сравнить с OP. Это в основном, почему вы не должны ставить асинхронные обратные вызовы внутри обещаний. Продвигайте все, что асинхронно, и тогда у вас нет этих ограничений. – jfriend00

+0

@ jfriend00 нравится? Редактирование с телефона. –

+0

@KevinB и все - спасибо за отличную дискуссию/комментарий. По вашему совету, я буду держать вещи просто, прощая все и используя «бросок» для ошибок. – Naresh

27

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

пример я видел, что помогли прояснить этот вопрос для меня было то, что вы можете установить функцию тайм-аута с отвергаем, например:

new Promise(_, reject) { 
setTimeout(reject, 3000); 
}); 

выше не мог бы возможно написать с броском.

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

+2

Спасибо, @Blondie. Это очень четкое описание разницы. – Naresh

+0

@Naresh, рад, что я мог бы помочь. – Blondie

+0

Это должен был быть принятый ответ, это просто и не путать –

87

Другим важным фактом является то, что reject()НЕ прекращает управление потоком подобно return оператор делает. В отличие от throw прекращает управление потоком.

Пример:

new Promise((resolve, reject) => { 
 
    throw "err"; 
 
    console.log("NEVER REACHED"); 
 
}) 
 
.then(() => console.log("RESOLVED")) 
 
.catch(() => console.log("REJECTED"));

против

new Promise((resolve, reject) => { 
 
    reject(); // resolve() behaves similarly 
 
    console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this 
 
}) 
 
.then(() => console.log("RESOLVED")) 
 
.catch(() => console.log("REJECTED"));

+1

спасибо, очень полезная информация –

+14

Ну, это правильно, но сравнение сложное. Поскольку обычно вы должны вернуть свое отклоненное обещание, написав 'return reject()', поэтому следующая строка не будет запущена. –

+2

Зачем вам это нужно? – lukyer

13

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

Ваш конкретный пример запутывает некоторые важные различия между ними:

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

Рассмотрит ситуацию ниже:

checkCredentials =() => { 
    let idToken = localStorage.getItem('some token'); 
    if (idToken) { 
     return fetch(`https://someValidateEndpoint`, { 
     headers: { 
      Authorization: `Bearer ${idToken}` 
     } 
     }) 
    } else { 
     throw new Error('No Token Found In Local Storage') 
    } 
    } 

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

try { 
    function onFulfilled() { ... do the rest of your logic } 
    function onRejected() { // handle async failure - like network timeout } 
    checkCredentials(x).then(onFulfilled, onRejected); 
} catch (e) { 
    // Error('No Token Found In Local Storage') 
    // handle synchronous failure 
} 

Не хорошо, и вот именно там, где Promise.reject (доступен в глобальном масштабе) приходит на помощь и эффективно дифференцирует себя от throw. Рефакторинг теперь становится:

checkCredentials =() => { 
    let idToken = localStorage.getItem('some_token'); 
    if (!idToken) { 
    return Promise.reject('No Token Found In Local Storage') 
    } 
    return fetch(`https://someValidateEndpoint`, { 
    headers: { 
     Authorization: `Bearer ${idToken}` 
    } 
    }) 
} 

Теперь это позволяет использовать только один catch() для сетевых сбоев и синхронная проверка ошибок из-за отсутствия маркеров:

checkCredentials() 
     .catch((error) => if (error == 'No Token') { 
     // do no token modal 
     } else if (error === 400) { 
     // do not authorized modal. etc. 
     } 
+1

Пример Op всегда возвращает обещание. Вопрос заключается в том, следует ли использовать 'Promise.reject' или' throw', когда вы хотите вернуть отклоненное обещание (обещание, которое перейдет к следующему '.catch()'). – marcospgp

+0

@maxwell - Мне нравится вам пример. В то же время, если на выборке вы добавите уловку, и в ней вы выбросите исключение, тогда вы будете в безопасности использовать try ... catch ... В потоке исключений нет идеального мира, но я думаю, что использование одного единый шаблон имеет смысл, и объединение шаблонов небезопасно (согласовано с вашим шаблоном против аналогии с шаблоном). – user3053247

1

Пример попробовать. Просто измените isVersionThrow на false, чтобы использовать reject вместо throw.

const isVersionThrow = true 
 

 
class TestClass { 
 
    async testFunction() { 
 
    if (isVersionThrow) { 
 
     console.log('Throw version') 
 
     throw new Error('Fail!') 
 
    } else { 
 
     console.log('Reject version') 
 
     return new Promise((resolve, reject) => { 
 
     reject(new Error('Fail!')) 
 
     }) 
 
    } 
 
    } 
 
} 
 

 
const test = async() => { 
 
    const test = new TestClass() 
 
    try { 
 
    var response = await test.testFunction() 
 
    return response 
 
    } catch (error) { 
 
    console.log('ERROR RETURNED') 
 
    throw error 
 
    } 
 
} 
 

 
test() 
 
.then(result => { 
 
    console.log('result: ' + result) 
 
}) 
 
.catch(error => { 
 
    console.log('error: ' + error) 
 
})

Смежные вопросы