Предположим, у меня есть следующий код.
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}
resolve(numerator / denominator);
});
}
Если моя цель состоит в том, чтобы использовать его reject
для досрочного выхода, должен ли я привыкнуть return
сразу же после этого?
Ответы:
return
Цель состоит в том, чтобы прекратить выполнение функции после отказа, и предотвратить выполнение кода после него.В этом случае он предотвращает
resolve(numerator / denominator);
выполнение, что не является строго необходимым. Однако все еще предпочтительнее прекратить выполнение, чтобы предотвратить возможную ловушку в будущем. Кроме того, рекомендуется избегать ненужного запуска кода.Задний план
Обещание может быть в одном из 3 состояний:
Когда обещание выполнено или отклонено, оно будет оставаться в этом состоянии неопределенно (урегулировано). Таким образом, отказ от выполненного обещания или выполнение отклоненного обещания не будет иметь эффекта.
Фрагмент этого примера показывает, что, хотя обещание было выполнено после отклонения, оно осталось отклоненным.
Так зачем нам возвращаться?
Хотя мы не можем изменить установленное состояние обещания, отклонение или разрешение не остановит выполнение остальной части функции. Функция может содержать код, который приведет к непонятным результатам. Например:
Даже если функция не содержит такого кода прямо сейчас, это создает возможную ловушку в будущем. Будущий рефакторинг может игнорировать тот факт, что код все еще выполняется после отклонения обещания, и его будет сложно отладить.
Остановка выполнения после разрешения / отклонения:
Это стандартный поток управления JS.
resolve
/reject
:Показать фрагмент кода
resolve
/reject
-, поскольку возвращаемое значение обратного вызова игнорируется, мы можем сохранить строку, вернув оператор reject / resol:Показать фрагмент кода
Показать фрагмент кода
Я предпочитаю использовать один из
return
вариантов, так как код более плоский.источник
return
он существует или нет, потому что после установки состояния обещания его нельзя изменить, поэтому вызовresolve()
после вызоваreject()
ничего не изменит, кроме использования нескольких дополнительных циклов ЦП. Я сам использовал быreturn
просто с точки зрения чистоты и эффективности кода, но это не требуется в этом конкретном примере.Promise.try(() => { })
вместо нового Promise и избегайте использования разрешения / отклонения вызовов. Вместо этого вы можете просто написать «return denominator === 0 ? throw 'Cannot divide by zero' : numerator / denominator;
Я использую»Promise.try
как средство для запуска Promise, а также исключить обещания, заключенные в блоки try / catch, которые являются проблематичными.reject
что делает что-то дорогое, например, подключение к базам данных или конечные точки API? Все это было бы ненужным и стоило бы вам денег и ресурсов, особенно, например, если вы подключаетесь к чему-то вроде базы данных AWS или конечной точки шлюза API. В этом случае вы определенно будете использовать возврат, чтобы избежать выполнения ненужного кода.return
.Распространенная идиома, которая может или не может быть вашей чашкой чая, состоит в том, чтобы объединить
return
сreject
, чтобы одновременно отклонить обещание и выйти из функции, так, чтобы остальная часть функции, включая функциюresolve
, не была выполнена. Если вам нравится этот стиль, он может сделать ваш код немного более компактным.Это работает отлично , так как конструктор Promise ничего не делает с любым возвращаемым значением, и в любом случае ,
resolve
иreject
возврата нет.Та же идиома может использоваться со стилем обратного вызова, показанным в другом ответе:
Опять же, это работает нормально, потому что вызывающий человек
divide
не ожидает, что он что-либо возвратит, и ничего не делает с возвращаемым значением.источник
reject
статусаТехнически это здесь не нужно 1 - потому что Обещание может быть разрешено или отклонено исключительно и только один раз. Первый результат Promise выигрывает, и каждый последующий результат игнорируется. Это отличается от обратных вызовов в стиле Node.
Это, как говорится, хорошая чистая практика, чтобы гарантировать, что точно один вызывается, когда это практически осуществимо, и, действительно, в этом случае, поскольку дальнейшая асинхронная / отложенная обработка не выполняется. Решение «вернуться рано» ничем не отличается от завершения любой функции, когда ее работа завершена, - против продолжения несвязанной или ненужной обработки.
Возврат в подходящее время (или иное использование условных выражений во избежание выполнения «другого» случая) снижает вероятность случайного запуска кода в недопустимом состоянии или выполнения нежелательных побочных эффектов; и как таковой он делает код менее подверженным неожиданному взлому.
1 Это технически ответ зависит также от того , что в этом случае код после «возвращения», она должна быть опущена, не приведет к побочному эффекту. JavaScript с радостью разделится на ноль и вернет либо + Infinity / -Infinity, либо NaN.
источник
Если вы не «вернетесь» после разрешения / отклонения, могут произойти плохие вещи (например, перенаправление страницы) после того, как вы намеревались остановить его. Источник: я столкнулся с этим.
источник
Ответ Ори уже объясняет, что в этом нет необходимости,
return
но это хорошая практика. Обратите внимание, что конструктор обещания безопасен для выброса, поэтому он будет игнорировать генерируемые исключения, переданные позже в пути, по сути, у вас есть побочные эффекты, которые вы не можете легко заметить.Обратите внимание, что
return
ранний вызов также очень распространен в обратных вызовах:Таким образом, хотя это хорошая практика в обещаниях, она требуется для обратных вызовов. Некоторые заметки о вашем коде:
источник
Во многих случаях можно проверить параметры отдельно и немедленно вернуть отклоненное обещание с помощью Promise.reject (причина) .
источник