Podczas programowania jednowątkowego programowania asynchronicznego znane mi są dwie główne techniki. Najczęstszym z nich jest użycie wywołań zwrotnych. Oznacza to przekazanie do funkcji, która działa asynchronicznie jako funkcja zwrotna jako parametr. Po zakończeniu operacji asynchronicznej wywołanie zwrotne zostanie wywołane.
Niektóre typowe jQuery
kody zaprojektowane w ten sposób:
$.get('userDetails', {'name': 'joe'}, function(data) {
$('#userAge').text(data.age);
});
Jednak ten typ kodu może być nieporządny i mocno zagnieżdżony, gdy chcemy wykonywać kolejne wywołania asynchroniczne jeden po drugim, gdy zakończy się poprzedni.
Drugim podejściem jest obietnica. Obietnica to obiekt reprezentujący wartość, która może jeszcze nie istnieć. Możesz ustawić wywołania zwrotne, które będą wywoływane, gdy wartość będzie gotowa do odczytu.
Różnica między obietnicami a tradycyjnym podejściem do wywołań zwrotnych polega na tym, że metody asynchroniczne teraz synchronicznie zwracają obiekty Promise, na które klient ustawia wywołanie zwrotne. Na przykład podobny kod przy użyciu Promises w AngularJS:
$http.get('userDetails', {'name': 'joe'})
.then(function(response) {
$('#userAge').text(response.age);
});
Więc moje pytanie brzmi: czy rzeczywiście istnieje prawdziwa różnica? Różnica wydaje się być czysto składniowa.
Czy istnieje głębszy powód, aby stosować jedną technikę nad drugą?
Odpowiedzi:
Można śmiało powiedzieć, że obietnice to tylko cukier syntaktyczny. Wszystko, co możesz zrobić z obietnicami, które możesz zrobić dzięki callbackom. W rzeczywistości większość obiecujących implementacji zapewnia sposoby konwertowania między nimi w dowolnym momencie.
Głównym powodem, dla którego obietnice są często lepsze, jest to, że łatwiej je skomponować , co z grubsza oznacza, że łączenie wielu obietnic „po prostu działa”, podczas gdy łączenie wielu połączeń zwrotnych często nie. Na przykład banalne jest przypisanie obietnicy do zmiennej i dołączenie do niej dodatkowych procedur obsługi, a nawet dołączenie procedury obsługi do dużej grupy obietnic, która zostanie wykonana dopiero po spełnieniu wszystkich obietnic. Chociaż można w pewien sposób emulować te rzeczy za pomocą wywołań zwrotnych, wymaga to znacznie więcej kodu, jest bardzo trudne do prawidłowego wykonania, a wynik końcowy jest zwykle o wiele trudniejszy do utrzymania.
Jednym z największych (i najsubtelniejszych) sposobów, w jakie obietnice zyskują swoją zdolność do kompozytu, jest jednolita obsługa wartości zwracanych i nieprzechwycone wyjątki. W przypadku wywołań zwrotnych sposób obsługi wyjątku może zależeć całkowicie od tego, która z wielu zagnieżdżonych wywołań zwrotnych go wyrzuciła, i która funkcja odbierająca wywołanie zwrotne ma próbę / catch w swojej implementacji. Dzięki obietnicom wiesz, że wyjątek, który wymyka się jednej funkcji zwrotnej, zostanie przechwycony i przekazany do procedury obsługi błędów dostarczonej z
.error()
lub.catch()
.W podanym przykładzie pojedynczego wywołania zwrotnego w porównaniu z jedną obietnicą, to prawda, że nie ma znaczącej różnicy. To kiedy masz zillion callback w porównaniu do zillion obietnic, kod oparty na obietnicach wygląda na znacznie ładniejszy.
Oto próba jakiegoś hipotetycznego kodu napisanego z obietnicami, a następnie z wywołaniami zwrotnymi, które powinny być na tyle skomplikowane, aby dać ci pojęcie o czym mówię.
Z obietnicami:
Z oddzwanianiem:
Mogą istnieć sprytne sposoby ograniczenia duplikacji kodu w wersji zwrotnej nawet bez obietnic, ale wszystkie, o których myślę, sprowadzają się do implementacji czegoś bardzo obiecującego.
źródło
yield
obietnic ed. Zaletą jest to, że masz możliwość mieszania w natywnych strukturach kontroli sterowania, które mogą różnić się liczbą wykonywanych operacji asynchronicznych. Dodam wersję, która to pokazuje.then(callback)
metody Promise, która akceptuje wywołanie zwrotne (zamiast metody API obsługującej to wywołanie zwrotne), nie musi nic robić z IoC. Promise wprowadza jeden poziom pośredni, który jest użyteczny przy komponowaniu, łańcuchowaniu i obsłudze błędów (w efekcie programowanie zorientowane na kolej), ale klient nie wykonuje jeszcze wywołania zwrotnego, więc tak naprawdę nie ma braku IoC.