Co to są odroczone połączenia zwrotne?

15

Rozumiem pomysł wywołania zwrotnego, w którym przekazuję funkcję do innej funkcji, a następnie ta funkcja korzysta z dostarczonej funkcji do woli.

Z trudem rozumiem odroczenie oddzwaniania, nawet po googlowaniu.

Czy ktoś mógłby podać proste wyjaśnienie? Programuję w Ruby, ale znam również C / C ++, ale przede wszystkim byłem doświadczonym programistą w asemblerze. Zastanawiam się więc, czy to trochę jak stos adresów zwrotnych, które się pojawiają? Mam nadzieję nauczyć się jquery lub node.js i te odroczone wywołania zwrotne wydają się integralną częścią obu. Rozumiem podstawowe zasady wątków (choć obiekt mutex powoduje ból głowy;)

dziesięć razy
źródło
Masz na myśli Deferredobiekty jQuery ? Czy chodzi o coś specyficznego dla Node.js?
bfavaretto
1
Nie, ogólnie mam na myśli. Chociaż chcę nauczyć się jquery i ewentualnie node.js, czułem, że muszę się dowiedzieć, co tak naprawdę jest odroczone oddzwanianie. Przeczytałem artykuł w Wikipedii na temat wywołań zwrotnych, ale nie mogłem zrozumieć odroczonych wywołań zwrotnych, które wydają się nieodłączną częścią paradygmatu działania asynchronicznego, który będzie dotyczył tych języków, które go używają.
1
Naprawdę proszę o koncepcyjny pomysł odroczonego oddzwaniania w przeciwieństwie do ich implementacji - przepraszam, jeśli nie wyjaśniłem tego bardziej jasno. Podałem przykłady języków, aby wyjaśnić pomysł, który staram się wyjaśnić, a także moje zaplecze programistyczne, aby ludzie wiedzieli, jak uzyskać odpowiedź. Bardzo dziękuję za dotychczasowe odpowiedzi - docieram!
tentimes
Ok, myślę, że mam go teraz, dzięki wam wszystkim! Nie wiem jednak, jak odpowiedzieć. Cameron wyjaśnił tę koncepcję najprościej i tego właśnie chciałem, ale inni też się włączyli i poszerzyli moją wiedzę. Nie jestem pewien, w jaki sposób przyjąć odpowiedź, ponieważ jestem nowy;)
tentimes

Odpowiedzi:

4

Na życzenie oto komentarze przedstawione jako odpowiedź:


Nie jestem pewien, czy całkowicie rozumiesz fakt, że funkcje w JS są obiektami pierwszej klasy i dlatego mogą być przechowywane do czasu, gdy będą potrzebne, po czasie ich utworzenia.

Na przykład powiedz, że chcesz zapisać do pliku, a następnie wydrukuj komunikat w dzienniku; więc wywołujesz funkcję „write ()” (lub cokolwiek innego) i przekazujesz jej funkcję, która generuje komunikat dziennika (jest to funkcja odroczonego oddzwaniania). „write ()” wewnętrznie przechowuje odniesienie do podanej funkcji, rozpoczyna zapis do pliku i ustawia własne wywołanie zwrotne, aby wiedzieć, kiedy zapis zostanie zakończony. Następnie powraca przed zakończeniem zapisu; kiedy to jest, wewnętrzne wywołanie zwrotne jest w jakiś sposób wywoływane (jest to zadanie frameworku - w przypadku node.js odbywa się to za pomocą pętli zdarzeń), która następnie wywołuje wywołanie zwrotne, które drukuje komunikat dziennika.

Część „odroczona” oznacza po prostu, że twoja funkcja zwrotna nie jest wywoływana od razu; wywoływanie go jest odraczane do odpowiedniego czasu. W przypadku funkcji asynchronicznych, takich jak wiele w node.js, dane wywołanie zwrotne jest generalnie wywoływane po zakończeniu operacji (lub wystąpi błąd).

Większość rzeczy jest asynchroniczna w node.js, ale w przeglądarce np. JQuery, większość rzeczy jest faktycznie synchroniczna (z wyjątkiem, oczywiście, dla żądań AJAX). Ponieważ funkcje pierwszej klasy są tak przydatne w JavaScript (szczególnie ze względu na doskonałą obsługę zamykania), wywołania zwrotne są również używane wszędzie w przeglądarce, ale nie są „odraczane” dla operacji synchronicznych (z wyjątkiem przypadków, gdy nie są wywoływane natychmiast przez Ty, ale później przez funkcję, którą wywołujesz).

Fakt, że system bazowy jest sterowany zdarzeniami, jest ortogonalny wobec korzystania z odroczonych wywołań zwrotnych; możesz sobie wyobrazić (bardzo wolną) wersję node.js, która uruchamiała wątek dla każdej operacji, a następnie wywołała określone wywołanie zwrotne, gdy wątek zakończył pracę, w ogóle nie wykorzystując zdarzeń. Oczywiście jest to okropny model, ale ilustruje mój punkt widzenia :-)

Cameron
źródło
8

Działanie odroczonego wywołania zwrotnego polega na każdym dodaniu do niego wywołania zwrotnego, które jest wypychane do tablicy. Następnie, gdy wywoływana jest metoda .resolve()lub .resolveWith()na odroczonym obiekcie, wszystkie .done()wywołania zwrotne w tablicy są wykonywane w kolejności.

Teraz możemy spojrzeć na to, czym jest Odroczony Obiekt. Weź poniższy fragment jako przykład.

var deferred = $.Deferred();
var promise = deferred.promise();

To, co mamy teraz, to odroczony obiekt i obietnica odroczonego obiektu. Odroczony obiekt ma wszystkie te same metody jak obiektu Obiecuję jednak przedmiotem obietnica ma tylko metody .done(), .fail()i .always()które są stosowane, aby dodać callbacków odroczonego obiektu dla siebie odpowiedni event. Z drugiej strony odroczony obiekt ma kilka innych metod, przede wszystkim .resolve()i .reject(). Po wywołaniu tych metod w odroczonym obiekcie wywoływane są wszystkie wywołania zwrotne. .resolve()odpala .done()i .always()wywołania zwrotne, podczas gdy wywołania .reject()metody .fail()i .always()wywołania zwrotne.

Zasadniczo odroczony obiekt jest ukryty w zakresie prywatnym, a obiekt obietnicy jest zwracany z funkcji, aby można było na nim umieścić wywołania zwrotne. Odroczony obiekt zostanie rozwiązany później, na przykład po zakończeniu żądania ajax lub po załadowaniu obrazu, po ustawieniu limitu czasu itp. Ważne jest również, aby zdawać sobie sprawę, że odroczony obiekt można rozwiązać tylko raz. Jeśli problem został już rozwiązany, wywołania zwrotne zostaną natychmiast wywołane.

Oto inny przykład, którego używam:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

Aby uzyskać więcej informacji na temat $.Deferred()metody jQuery i obiektów odroczonych, odwiedź http://api.jquery.com/category/deferred-object/

użytkownik400654
źródło
Będzie to prawdopodobnie nieocenione, gdy przejdę do koncepcji odroczonego oddzwaniania. Przepraszam, ale wciąż nie rozumiem pojęcia, czym jest odroczenie oddzwonienia. Bardziej szukam koncepcyjnego pomysłu. W pewnym sensie według pomysłu Mihii. Kiedy już zdołam się rozejrzeć, to może zrozumiem js.
tentimes
3

Nie jestem pewien, ale uważam, że odroczone oddzwonienie odnosi się do asynchronicznego oddzwonienia, więc lepiej będzie, jeśli będziesz go szukać w Google.

Najlepsze wytłumaczenie, jakie znalazłem, to http://www.nodebeginner.org

Hej, prawdopodobnieExpensiveFunction (), proszę, zróbcie swoje rzeczy, ale ja, pojedynczy wątek Node.js, nie zamierzam czekać tutaj, aż skończycie, będę nadal wykonywać wiersze kodu poniżej, więc proszę to callbackFunction () tutaj i wywołać go, gdy skończysz robić swoje drogie rzeczy? Dzięki!"

W tym przykładzie prawdopodobnieExpensiveFunction jest funkcją nieblokującą (lub funkcją asynchroniczną). Oznacza to, że nie jest on wykonywany od razu, ale umieszczany w tak zwanej pętli zdarzeń. Wątek node.js będzie kontynuował wykonywanie, ale w pewnym momencie zdecyduje się wykonać coś z pętli zdarzeń. Kiedy osiągnie prawdopodobnieExpensiveFunction, wywołuje ją, a kiedy prawdopodobnieExpensiveFunction kończy wykonywanie, wywołuje (odroczone) wywołanie zwrotne przekazane jako parametr do niego.

Jako przykład prawdopodobnieExpensiveFunction możesz wziąć fs.readFile

Mihai
źródło
Dzięki. Ale w jaki sposób będzie to kosztowna funkcja, jeśli już powróciła i jesteś ponownie w głównym wątku wykonania? Nie rozumiem tego. Czy mówisz, że funkcja w jakiś sposób utrzymuje się po zakończeniu?
Zredagowałem odpowiedź, może teraz jest jaśniejsza.
Bardzo pomocny. Ale ... czy muszę przetworzyć tę tablicę przechowywanych wywołań zwrotnych? Mam na myśli to, co przetwarza tę listę. Czy to (na przykład) js podnosi te wywołania zwrotne w tle, gdy nie musisz nic z tym zrobić, czy też zdarzenie powoduje, że node.js lub coś wywołuje określone wywołanie zwrotne. Przepraszam, otrzymuję około 70% tego, co mówisz, ale jestem trochę zagubiony w pozostałych :)
tentimes
@tentimes - „co to jest przetwarzające tę listę” obiekt $ .Deferred () przetwarza listę. Podczas wywoływania .resolve()lub .reject()na oryginalnym odroczonym obiekcie wywoływana jest lista oddzwonień.
user400654
2
@tentimes: Z tego, co mówisz, nie jestem pewien, czy całkowicie rozumiesz fakt, że funkcje w JS są obiektami pierwszej klasy, a zatem mogą być przechowywane do momentu, gdy będą potrzebne, po czasie, w którym zostały utworzone. Na przykład powiedz, że chcesz zapisać do pliku, a następnie wydrukuj komunikat w dzienniku; więc wywołujesz funkcję „zapisu” (lub cokolwiek innego) i przekazujesz jej funkcję, która generuje komunikat dziennika. „write ()” wewnętrznie przechowuje odniesienie do podanej funkcji, rozpoczyna zapis do pliku i ustawia własne wywołanie zwrotne, aby wiedzieć, kiedy zapis zostanie zakończony. Następnie powraca przed zakończeniem zapisu; kiedy jest, twoja funkcja jest wywoływana.
Cameron,
3

JavaScript jest jednowątkowy, więc nie możesz myśleć w kategoriach wątków, aby to zrozumieć. Oto przykład zwykłych i asynchronicznych wywołań zwrotnych przy użyciu jQuery:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);
bfavaretto
źródło
Teraz mnie to gdzieś prowadzi, dzięki. Tak więc asynchroniczny jest odpowiedzią na zdarzenie, które mam skonfigurowane za pomocą ajax - to po prostu farmuje to i jeśli zdarzenie się zdarzy, moje wywołanie zwrotne zostanie wywołane? Myślę, że rozumiem. Czy node.js / jquery zrobiłby coś podobnego z jquery korzystającym z odroczonych obiektów i skomplikowanym systemem interakcji z nimi, aby po prostu zrobić to samo, ale używając metod?
tentimes
1
@tentimes, Dokładnie! Oddzwanianie zwykle jest uruchamiane w odpowiedzi na zdarzenia (ale ponieważ „oddzwanianie” nie jest konstrukcją języka js, czasami termin ten jest używany w innych kontekstach). Odroczone obiekty (obietnice), które widzisz w odpowiedzi Kevina, to w zasadzie cukier składniowy. Są one „rozwiązane” lub „odrzucone”, gdy zostanie wywołane jakieś (asynchroniczne) zdarzenie, a następnie wywołują odpowiednie wywołanie zwrotne („zrobione” lub „niepowodzenie”, a następnie „zawsze”). Używanie ich w jQuery może sprawić, że kod będzie bardziej czytelny i pozwoli na kilka dodatkowych sztuczek (na przykład łatwe dodanie drugiego wywołania zwrotnego po uruchomieniu żądania ajax).
bfavaretto,
Oba są asynchronicznymi wywołaniami zwrotnymi
Raynos,
1

Odroczone wywołania zwrotne (inaczej Promices ) umożliwiają pisanie sekwencyjnego kodu asynchronicznego, bez bólu i spaghetti zwrotnego:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

„when” pozwala poczekać, aż funkcje powrócą równolegle, i thenmoże być sekwencyjnie powiązane.

jedna uwaga: jQuery odroczony ! = Obietnice / A , ich składnia jest nieco inna.

Istnieją dobre artykuły na ten temat: jeden na IEBlog, a drugi na jakimś losowym blogu , książka i popularne pytanie dotyczące nakładania stosów

c69
źródło
1
uhh .. okazuje się, że OP poprosił nieco inną rzecz… cóż, miejmy nadzieję, że ta odpowiedź pomoże komuś innemu, może kiedyś.
c69,