Załóżmy, że mam następujący kod.
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if(denominator === 0){
reject("Cannot divide by 0");
return; //superfluous?
}
resolve(numerator / denominator);
});
}
Jeśli moim celem jest reject
wcześniejsze wyjście, czy powinienem return
nawykć zaraz po tym?
Odpowiedzi:
return
Celem jest, aby zakończyć wykonywanie funkcji po odrzuceniu i zapobiec wykonanie kodu po niej.W takim przypadku uniemożliwia
resolve(numerator / denominator);
wykonanie polecenia, które nie jest ściśle potrzebne. Jednak nadal lepiej jest zakończyć wykonywanie, aby zapobiec możliwej pułapce w przyszłości. Ponadto dobrą praktyką jest zapobieganie niepotrzebnemu uruchamianiu kodu.tło
Obietnica może być w jednym z 3 stanów:
Kiedy obietnica zostanie spełniona lub odrzucona, pozostanie w tym stanie na czas nieokreślony (rozliczony). Odrzucenie spełnionej obietnicy lub spełnienie odrzuconej obietnicy nie przyniesie skutku.
Ten przykładowy fragment pokazuje, że chociaż obietnica została spełniona po odrzuceniu, pozostała odrzucona.
Dlaczego więc musimy wrócić?
Chociaż nie możemy zmienić ustalonego stanu przyrzeczenia, odrzucenie lub rozstrzygnięcie nie zatrzyma wykonania pozostałej części funkcji. Funkcja może zawierać kod, który spowoduje mylące wyniki. Na przykład:
Nawet jeśli funkcja nie zawiera obecnie takiego kodu, tworzy to potencjalną pułapkę na przyszłość. Przyszły refaktor może zignorować fakt, że kod jest nadal wykonywany po odrzuceniu obietnicy i będzie trudny do debugowania.
Zatrzymywanie wykonywania po rozwiązaniu / odrzuceniu:
Jest to standardowy przepływ kontroli JS.
resolve
/reject
:Pokaż fragment kodu
resolve
/reject
- ponieważ zwracana wartość wywołania zwrotnego jest ignorowana, możemy zapisać linię, zwracając instrukcję odrzucenia / rozwiązania:Pokaż fragment kodu
Pokaż fragment kodu
Wolę użyć jednej z
return
opcji, ponieważ kod jest bardziej płaski.źródło
return
jest, czy nie, ponieważ po ustawieniu stanu obietnicy nie można go zmienić, więc wywołanieresolve()
po wywołaniureject()
nie zrobi nic oprócz użycia kilku dodatkowych cykli procesora. Ja sam użyłbymreturn
sprawiedliwego z punktu widzenia czystości i wydajności kodu, ale nie jest to wymagane w tym konkretnym przykładzie.Promise.try(() => { })
zamiast nowej Obietnicy i unikaj używania rozstrzygania / odrzucania połączeń. Zamiast tego możesz po prostu napisać,return denominator === 0 ? throw 'Cannot divide by zero' : numerator / denominator;
że używamPromise.try
jako środka do rozpoczęcia Obietnicy, a także do wyeliminowania obietnic zawartych w blokach try / catch, które są problematyczne.reject
, co robi coś kosztownego, na przykład podłącz do baz danych lub punktów końcowych API? Wszystko to byłoby niepotrzebne i kosztowało cię pieniądze i zasoby, szczególnie na przykład, jeśli łączysz się z czymś takim jak baza danych AWS lub punkt końcowy API Gateway. W takim przypadku zdecydowanie użyłbyś znaku powrotu, aby uniknąć wykonania niepotrzebnego kodu.return
.Powszechnym idiomem, który może, ale nie musi, być twoja filiżanka herbaty, jest łączenie się
return
z niąreject
, aby jednocześnie odrzucić obietnicę i wyjść z funkcji, aby pozostała część funkcji, w tym funkcja,resolve
nie została wykonana. Jeśli podoba Ci się ten styl, może sprawić, że Twój kod będzie nieco bardziej zwarty.Działa to dobrze, ponieważ konstruktor Promise nic nie robi z żadną wartością zwracaną, aw każdym razie
resolve
ireject
powrotnej nic.Tego samego idiomu można użyć ze stylem wywołania zwrotnego pokazanym w innej odpowiedzi:
Ponownie działa to dobrze, ponieważ osoba dzwoniąca
divide
nie oczekuje, że cokolwiek zwróci i nie zrobi nic z wartością zwracaną.źródło
reject
statusuTechnicznie nie jest to tutaj potrzebne 1 - ponieważ obietnica może zostać rozpatrzona lub odrzucona, wyłącznie i tylko raz. Pierwszy wynik Obietnicy wygrywa, a każdy kolejny wynik jest ignorowany. To jest inne od wywołań zwrotnych w stylu węzła.
Biorąc to pod uwagę, dobrą czystą praktyką jest upewnienie się, że dokładnie jedna jest wywoływana, gdy jest to praktyczne, a w tym przypadku, ponieważ nie ma dalszego asynchronizacji / odroczenia przetwarzania. Decyzja o „wczesnym powrocie” nie różni się niczym od zakończenia jakiejkolwiek funkcji po zakończeniu pracy - w przeciwieństwie do kontynuowania niepowiązanego lub niepotrzebnego przetwarzania.
Zwrot w odpowiednim czasie (lub użycie warunkowe w inny sposób, aby uniknąć wykonania „innego” przypadku) zmniejsza ryzyko przypadkowego uruchomienia kodu w nieprawidłowym stanie lub wykonania niepożądanych efektów ubocznych; i jako taki sprawia, że kod jest mniej podatny na „nieoczekiwane zerwanie”.
1 Ta odpowiedź techniczna zależy również od tego, że w tym przypadku kod po „powrocie”, jeśli zostanie pominięty, nie spowoduje skutku ubocznego. JavaScript szczęśliwie podzieli przez zero i zwróci + Infinity / -Infinity lub NaN.
źródło
Jeśli nie „wrócisz” po rozwiązaniu / odrzuceniu, złe rzeczy (takie jak przekierowanie strony) mogą się zdarzyć po tym, jak chciałeś to zatrzymać. Źródło: Wpadłem na to.
źródło
Odpowiedź Ori już wyjaśnia, że nie jest to konieczne
return
ale jest to dobra praktyka. Zauważ, że konstruktor obietnicy jest bezpieczny, więc zignoruje rzucone wyjątki, które minęły później na ścieżce, w zasadzie masz efekty uboczne, których nie możesz łatwo zaobserwować.Zauważ, że
return
wczesne ing jest również bardzo częste w callbackach:Tak więc, chociaż jest to dobra praktyka w obietnicach, jest wymagana w przypadku wywołań zwrotnych. Kilka uwag na temat Twojego kodu:
źródło
W wielu przypadkach można osobno zweryfikować parametry i natychmiast zwrócić odrzuconą obietnicę za pomocą Promise.reject (powód) .
źródło