2010-10-15 24 views
9

Ten przykład to JavaScript, ponieważ tam najczęściej używam wywołań zwrotnych. Chcę zrozumieć, jak działają na niskim poziomie.Czy połączenia zwrotne są zawsze asynchroniczne?

W poniższym przykładzie oczekiwałbym, że wszystko się wydarzy i "oddzwonienie" nastąpi po "kroku 3" i przed "krokiem 4." Ma to dla mnie sens, ponieważ wszystko dzieje się po jednym wątku egzekucji. Nie ma oszustwa. Jedyną rzeczą, która jest wyjątkowa, jest to, że przekazałeś funkcję innej funkcji.

function main() { 
    console.log("step 1"); 
    console.log("step 2"); 
    doSomething(myCallBack); 
    console.log("step 4"); 
} 

function doSomething(f) { 
    accessTheDatabase(); // this could take a while 
    console.log("step 3"); 
    f(); // done - now call back 
} 

function myCallBack() { 
    console.log("calling back!"); 
} 

Jak byś zrobić doSomething asynchroniczny tak, że „krok 4” może być wykonywane przed lub równolegle z „etap 3”?

Zakładam, że gdyby doSomething było asynchronicznie nazwane, musiałoby to dotyczyć innego wątku, nie? A jeśli tak, kiedy kończy się, a następnie wywołuje myCallBack, , czy wywołanie zwrotne ma miejsce w drugim wątku lub w głównym wątku? Jeśli dzieje się to w głównym wątku, dlaczego drugi wątek potrzebuje nawet wskaźnika do funkcji zwrotnej? Jak działa połączenie między wątkami?

+0

Zakładam, że to * nie * działa w przeglądarce, prawda? Ponieważ w przeglądarce każde wywołanie AJAX jest z konieczności asynchroniczne ... –

+2

@Dean, przede wszystkim żądania XHR mogą być synchroniczne (w zależności od parametrów żądania). Po drugie, jeśli przeczytasz pytanie (i spojrzysz na jego przykładowy kod), nie chodzi o Ajax. – eyelidlessness

+0

@ Dean może być uruchomiony w przeglądarce lub nie. Najbardziej interesuje mnie ustalenie, czy funkcja wywołania zwrotnego jest wykonywana w wątku głównym, czy w drugim wątku, który został przekazany jako wskaźnik funkcji wywołania zwrotnego. –

Odpowiedz

11

WebWorkers na bok, model programowania JavaScript w przeglądarce jest czysto jednowątkowy. można dokonać połączenia nieco asynchroniczny przy użyciu window.setTimeout:

window.setTimeout(doSomething, 0, myCallBack); 

To skutecznie stawia wezwanie doSomething(myCallBack) na kolejce timera, a po 0 lub więcej milisekund upłynąć, to w końcu się powoływać. Jednak, podobnie jak w przypadku wszystkich asynchronicznych wywołań JavaScript, musisz zrezygnować z kontekstu wykonania, zanim będzie można wywołać asynchroniczne wywołania zwrotne; oznacza to, że kolejka zegara nie zostanie przetworzona (a zatem doSomething(myCallBack) nie zostanie wywołana), dopóki nie zakończy się twoja funkcja main(), zakładając, że to koniec twojego JavaScript.

Jedną z niefortunnych konsekwencji tego podejścia jest to, że doSomething(myCallBack) nie jest wywoływane równolegle z console.log("step 4"). Z drugiej strony, rozważ XMLHttpRequest.send; po wykonaniu tego połączenia pozostała część JS może kontynuować wykonywanie, gdy przeglądarka zgłasza żądanie HTTP. Twój skrypt musi zostać zakończony przed wykonaniem obsługi onreadystatechange, ale większość operacji połączenia HTTP może odbywać się równolegle podczas wykonywania JS.

+0

W przypadku 'XMLHttpRequest.send' zakładam, że dzieje się to w innym wątku. Kiedy to zrobi i uruchomi się program 'onreadystatechange', w którym wątku to się dzieje? –

+1

To dzieje się w głównym wątku JavaScript. W praktyce, może to być dowolny wątek, ale konceptualnie JavaScript (i DOM, jeśli o to chodzi) wykonuje się w jednym wątku. – ide

+1

Sądzę, że mylące jest to, że nazywa się to "oddzwanianiem". To dla mnie mówi "tutaj jest funkcja, proszę, zadzwoń, kiedy skończysz robić swoje rzeczy. Będę robił swoje." Kiedy tak naprawdę przeglądarka zakończy wywołanie AJAX, a następnie przerwie wątek główny (za pośrednictwem jakiego mechanizmu?), A sam wątek główny wywoła funkcję, która została zarejestrowana jako wywołanie zwrotne. Czy mam rację? –

0

Do wykonania tej czynności potrzebne byłyby wiele wątków wykonawczych, co do których nie wierzę, że można zrobić w JavaScript (chociaż popraw mnie jeśli się mylę). Jeśli jednak pisałeś program C/C++, spójrz na pakiet pthreads (lub libdispatch na Mac OS X 10.6).

Edytuj: wyszukiwanie w Google dla "wątków javascript" okazuje się być może interesującymi wynikami.

0

Korzystanie z oddzwonień w taki sam sposób jak (nazwa deklaracji funkcji lub nazwa zmiennej funkcji wyrażenia jako argument innej funkcji), są one synchroniczne. Aby były asynchroniczne, można je opakować w postaci setTimeout.

+0

@trinithis, jak się mylę? – eyelidlessness

5

Hmmm .. coś wygląda nie tak (zrobiłem v trochę kodu JavaScript): przekazujesz myCallBack do funkcji doSomething(), ale nie odwołujesz go !? Musiałbyś mieć wywołanie funkcji f() wewnątrz funkcji doSomething() lub przekazać ją innej funkcji, która wywoła ją ponownie po zakończeniu długiej operacji. Żadne wywołania zwrotne nie są z natury asynchroniczne - w twoim przypadku wszystko uruchamiasz w tym samym wątku (nawet jeśli accessTheDatabase() jest asynchroniczne, w takim przypadku natychmiast powróciłoby!) - więc nadal będzie to Krok 1, Krok 2, Krok 3, Krok 4. Wierzę chcesz:

function main() { 
    console.log("step 1"); 
    console.log("step 2"); 
    doSomething(myCallBack); 
    console.log("step 4"); 
} 

function doSomething(f) { 
    accessTheDatabase(f); // assuming this is an asynchronous operation and calls the callback f once done 
} 

function myCallBack() { 
    console.log("step 3"); 
} 

W odpowiedzi na drugą część pytania: wywołanie zwrotne będzie działać na których kiedykolwiek wątku dzwonisz go od - uruchomić oddzwanianie w innym wątku trzeba by join() najpierw wątek, a następnie wywołanie() lub begininvoke() wywołanie zwrotne - chociaż niektóre z nich mogą już być wbudowane, aby wywołać wywołanie zwrotne w kolejce rzeczy do uruchomienia w wątku, który ma być uruchamiany (często skrzynka z wątkami UI) UWAGA: Może już być, że dostęp do bazy danych() uruchamia wywołanie zwrotne w wątku, który ją wywołał - używając jednej z wyżej wymienionych metod ...

+0

Masz rację! Dzięki za połów. –

+0

Moja przyjemność, zaznacz jako odpowiedź, jeśli jest :) – markmnl

+0

zaktualizowana odpowiedź na drugą część pytania - który wątek jest uruchamiany na – markmnl

Powiązane problemy