2011-10-13 13 views
22

Mam obsługę zdarzeń, ale chcę się upewnić, że będzie czekać, aż wszystkie inne zdarzenia w kolejce zdarzeń zostaną wykonane.Jak uruchomić kod po obsłużeniu wszystkich innych zdarzeń

Na przykład mam kilka zakładek na stronie. Mam ogólny kod do obsługi kart, które zakładają zakładkę "Aktywna karta", gdy użytkownik ją kliknie.

$('a.tab').click(function() { 
    $(this).parent('div').find('a.tab').removeClass('activeTab'); 
    $(this).addClass('activeTab'); 
}); 

Dla określonego zestawu zakładek, mogę mieć Handler:

// handler-1 
$('div#myTabs a.tab').click(function() { 
    do_something(); 
}); 

function do_something() { 
    var type = $('div#myTabs a.activeTab').data('type'); 
    do_something_else(type); 
} 

do_something() może uzyskać wywołana w odpowiedzi na inne działania poza klikając na zakładkę, ale niezależnie od tego, jak go zostaje wywołana, chce wiedzieć, jaka jest aktywna karta, zanim będzie mogła kontynuować.

Mój problem polega na tym, że jeśli jest on wywoływany przez kod pod "// handler-1", klasa "activeTab" mogła jeszcze nie zostać zresetowana, więc wartość, którą pobierze dla "type", nadal będzie z jakiegokolwiek znacznika został wybrany przed kliknięciem na ten.

Rozwiązałem to tak:

// handler-1 
$('div#myTabs a.tab').click(function() { 
    set_timeout(function() { 
    do_something(); 
    }, 100); 
}); 

To wygląda zbyt dużo kludge żeby mnie zadowolić. Skąd mam wiedzieć, że program obsługi zdarzeń zegara zostanie wywołany dopiero po tym, jak wszystkie pozostałe moduły obsługi mają swoją kolej? Na pewno mógłbym zmienić "100" na "1000" lub nawet "10000", ale chciałbym również zwiększyć wydajność transakcji (i wciąż nie ma pewności, ponieważ nawet 10 sekund może nie wystarczyć na przykład w przeglądarce na komputerze, który jest wystarczająco okaleczony).

widziałem kilka możliwych rozwiązań:

ale żadna z nich nie są na tyle ogólne, aby mnie zadowolić. Nie próbuję uruchomić programu obsługi najpierw. Zamiast tego, chcę coś takiego:

function do_something() { 
    $.when_all_other_events_have_been_handled(function() { 
    do_something(); 
    }); 
}); 

Czy coś takiego istnieje?

Spojrzałem na $ .fn.when (arg) .done(), ale kiedy co? "arg" w tym przypadku musiałby być obiekt odroczony, który wykonuje wszystko, co jest już w kolejce uruchamiania. Catch-22!

Sproutcore ma coś w rodzaju "engine.run()" (nie pamiętam dokładnej nazwy), która powróci tylko wtedy, gdy wszystkie inne zdarzenia w "silniku" zostały obsłużone, ale nie mogę znaleźć czegoś takiego w jQuery. (http://api.jquery.com/category/events/). Jeśli ktoś wie o czymś takim, proszę dać mi znać!

Dzięki! :)

Odpowiedz

27

Spróbuj tego:

function postpone(fun) 
{ 
    window.setTimeout(fun,0); 
} 

więc jeśli będziesz dzwonić postpone(do_something); że do_something zostanie wykonana po wszystkich zdarzeń interfejsu użytkownika, które są w kolejce zdarzeń dla momentu postpone() rozmowy.

+0

Hej! Pokonałeś mnie do własnej odpowiedzi! –

+1

Użyłem tego z dodatnim czasem oczekiwania i uznałem, że to był wyścig, zadowolony, że jest ważny :) – Jake

+0

Wystąpił błąd w obliczu użycia funkcji odroczenia: błąd bezużyteczne wywołanie setTimeout (brakujące cytaty wokół argumentu?) W FireFox 20.0 dla kanoników Ubuntu 1.0. @ Lsiden odpowiedź zadziałała dla mnie. –

25

może Znalazłem odpowiedź tutaj: http://ejohn.org/blog/how-javascript-timers-work/

Według J.Resig, jeśli robię

setTimeout(function() { 
    do_something(); 
}, 0); 

funkcja anonimowa dostanie enqued natychmiast, ale nie będzie się nazywa, aż wszystko w kolejce zdarzeń już obsługiwane. Oznacza to, że niezależnie od tego, jakiej przeglądarki używa, naprawdę działa wszystko na zasadzie "pierwsze przyszło-pierwsze-pierwsze" tak, jak oczekiwałbym. Jeśli z jakiegoś powodu silnik JavaScript podejmie się samodzielnej zmiany kolejności zdarzeń w kolejce (nie wiem, dlaczego tak powinno być, ale nigdy nie wiadomo, od AFAIK Nigdy nie widziałem żadnej takiej gwarancji w standardach, ale potem trzeba spojrzeć ponownie), wtedy wszystkie zakłady są wyłączone!

+0

Niedostrzeganie tego zachowania w przeglądarce Chrome. Mam 2 oddzielne funkcje wywoływane w przypadku "kliknięcia" pola wyboru. Na tym, który chcę ostatni, zawinąłem go w setTimeout, ale jeśli ustawię go na 0 .. to wydaje się być stanem wyścigowym. Ustawiłem go na 500 i wydaje się, że działa, ale obawiam się, że to tylko dzięki szczęściu. – Dss

Powiązane problemy