Dlaczego setTimeout nie anuluje mojej pętli?

Zastanawiałem się, ile razy Instrukcja JavaScript while (w konsoli Chrome) może zwiększyć zmienną w milisekundzie, więc szybko napisałem ten fragment bezpośrednio do konsoli:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
Problem w tym, że działa w nieskończoność.
Dlaczego tak się dzieje i jak Mogę to rozwiązać?
Author: laurent, 2014-02-09

6 answers

To wraca do jednowątkowej natury JavaScript1. To co się dzieje to mniej więcej tak:

  1. Twoje zmienne są przypisane.
  2. planujesz funkcję, aby ustawić run = false. To jest zaplanowane do uruchomienia po bieżąca funkcja jest uruchomiona (lub cokolwiek innego jest aktualnie aktywne).
  3. masz swoją nieskończoną pętlę i pozostań wewnątrz bieżącej funkcji.
  4. po twojej niekończącej się pętli ( never ), wywołanie zwrotne setTimeout() zostanie wykonane i run=false.

Jak widzisz, podejście setTimeout() nie zadziała tutaj. Możesz to obejść, sprawdzając czas w stanie while, ale to zakłóci rzeczywisty pomiar.

1 przynajmniej dla bardziej praktycznych celów można go zobaczyć jako jednowątkowy. W rzeczywistości istnieje tzw. "pętla zdarzeń". W tej pętli wszystkie funkcje są kolejkowane do czasu ich wykonania. Jeśli ustawisz w kolejce nową funkcję, zostanie ona umieszczona w odpowiedniej pozycji wewnątrz tej kolejki. Po zakończeniu bieżącej funkcji silnik pobiera następną funkcję z kolejki (w odniesieniu do timingów wprowadzonych np. przez setTimeout() i wykonuje ją.
W rezultacie w każdym momencie wykonywana jest tylko jedna funkcja, co sprawia, że wykonanie jest prawie jednowątkowe. Istnieją pewne wyjątki dla wydarzeń, które zostały omówione w poniższym linku.


Dla Referencja:

 80
Author: Sirko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

JavaScript jest jednowątkowy, więc gdy jesteś w pętli, nic innego nie jest wykonywane.

 24
Author: laurent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-12 17:50:14

Aby zachować prawdziwą prędkość Chrome bez konieczności ciągłego pobierania czasu do obliczenia prędkości, możesz wypróbować ten kod JS:

var start = new Date().getTime()
var i = 0
while(i<1000000)
{
    i++
}
var end = new Date().getTime()
var delta = end-start
var speed = i/delta
console.log(speed + " loops per millisecond")
 19
Author: SyntaxLAMP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 13:29:39

Javascript jest jednowątkowy, co oznacza, że uruchamia tylko jedną instrukcję na raz, sekwencyjnie.

System zdarzeń, podobnie jak w wielu innych językach i bibliotekach, jest obsługiwany przez pętlę zdarzeń. Pętla zdarzeń jest w zasadzie pętlą, która na każdej iteracji sprawdza, czy nie ma wiadomości w kolejce, a zdarzenia dispatch.

W javascript (jak w mot języków implementujących ten wzorzec), pętla zdarzeń jest wywoływana, gdy stos jest pusty, to znaczy, gdy wszystkie funkcje mają zwroty, w innych word, na końcu kodu programu.

Twój "prawdziwy" program wygląda mniej więcej tak za sceną:

var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }

while(true) {
/*
 * check for new messages in the queue and dispatch
 * events if there are some
 */
  processEvents();
}

Więc wiadomość z zegara mówiąca, że timeout się skończył, nigdy nie jest przetwarzana.

Więcej informacji o pętli zdarzeń na : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop


Oczywiście jest to nieco bardziej złożone, sprawdź tutaj te przykłady : czy JavaScript jest gwarantowany jako jednowątkowy? (tl; dr: W niektóre silniki przeglądarki, niektóre zdarzenia zewnętrzne nie są zależne od pętli zdarzeń i są natychmiast uruchamiane, gdy wystąpią, uprzedzając bieżące zadanie. Ale tak nie jest w przypadku setTimeout, który po prostu dodaje wiadomość do kolejki i nigdy nie jest uruchamiany od razu.)

 4
Author: jillro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:35

Pętla While nie ma dostępu do setTimeout. Masz kod, który ustawia run true, a wtedy nigdy nie stanie się fałszywy.

 2
Author: ChriskOlson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-09 20:06:28

JavaScript ma pojedynczy wątek i ma pojedynczy wątek w dowolnym miejscu.

Myślę, że to pytanie jest dobre: czy JavaScript może być jednowątkowy?

Gdy twój kod jest w pętli, inne ocde nie wykonują i nie blokują.

 1
Author: Community,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:37