Pertanyaan Mengapa setTimeout membatalkan loop saya?


Saya bertanya-tanya berapa kali bisa JavaScript while pernyataan (di konsol Chrome) dapat menaikkan variabel dalam milidetik, jadi saya segera menulis cuplikan ini langsung ke konsol:

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

Masalahnya adalah itu berjalan selamanya.
Mengapa ini terjadi, dan bagaimana saya bisa menyelesaikannya?


75
2018-02-09 08:04


asal


Jawaban:


Ini kembali ke sifat satu-threaded dari JavaScript1. Apa yang terjadi cukup banyak ini:

  1. Variabel Anda ditetapkan.
  2. Anda menjadwalkan fungsi, untuk mengatur run = false. Ini dijadwalkan untuk dijalankan setelah fungsi saat ini dijalankan (atau apa pun yang saat ini aktif).
  3. Anda memiliki lingkaran tanpa akhir Anda dan tetap berada di dalam fungsi saat ini.
  4. Setelah lingkaran tanpa akhir Anda (tak pernah), yang setTimeout() panggilan balik akan dieksekusi dan run=false.

Seperti yang Anda lihat, a setTimeout() pendekatan tidak akan berfungsi di sini. Anda dapat mengatasi itu dengan memeriksa waktu di while kondisi, tetapi ini akan mengutak-atik pengukuran aktual Anda.

1 Setidaknya untuk tujuan yang lebih praktis Anda dapat melihatnya sebagai single-threaded. Sebenarnya ada yang disebut "event-loop". Dalam lingkaran itu semua fungsi diantrekan sampai mereka dieksekusi. Jika Anda mengantre fungsi baru, itu diletakkan di posisi masing-masing di dalam antrian itu. Setelah fungsi saat ini telah selesai, mesin mengambil fungsi berikutnya dari antrian (sehubungan dengan timing seperti yang diperkenalkan, misalnya, oleh setTimeout() dan mengeksekusinya.
Akibatnya pada setiap titik waktu hanya satu fungsi yang dieksekusi, sehingga membuat eksekusi cukup banyak ulir tunggal. Ada beberapa pengecualian untuk acara, yang dibahas di tautan di bawah ini.


Sebagai referensi:


81
2018-02-09 08:10



JavaScript adalah single-threaded jadi, sementara Anda berada di loop, tidak ada lagi yang dieksekusi.


24
2018-02-09 08:11



Untuk menjaga kecepatan Chrome sesungguhnya tanpa harus terus-menerus mengambil waktu untuk menghitung kecepatan, Anda dapat mencoba kode JS ini:

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
2018-02-09 13:29



Javascript adalah single-threaded, yang berarti ia hanya menjalankan satu instruksi pada satu waktu, secara berurutan.

Sistem acara, seperti dalam banyak bahasa dan pustaka lainnya, ditangani oleh perulangan peristiwa. Peristiwa loop pada dasarnya adalah sebuah loop, yang pada setiap iterasi memeriksa pesan dalam antrian, dan mengirimkan peristiwa.

Dalam javascript (seperti dalam bahasa yang mengimplementasikan pola ini), loop peristiwa dipanggil ketika stack kosong, artinya, ketika semua fungsi kembali, dengan kata lain, di akhir kode program.

Program "nyata" Anda terlihat seperti ini di belakang layar:

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();
}

Jadi pesan dari jam yang mengatakan waktu habis sudah tidak pernah diproses.

Info lebih lanjut tentang perulangan acara: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop


Tentu saja ini sedikit lebih rumit, lihat di sini contoh-contoh itu: Apakah JavaScript dijamin akan single-threaded? (tl; dr: Di beberapa mesin browser, beberapa peristiwa eksternal tidak bergantung pada lingkaran acara dan segera diaktifkan ketika terjadi, mendahului tugas saat ini. Tetapi ini tidak terjadi dengan setTimeout, yang hanya menambahkan pesan ke antrian dan tidak pernah langsung menyala.)


4
2018-02-09 15:16



Loop Sementara tidak mengakses setTimeout. Anda memiliki kode yang mengatur berjalan benar, dan kemudian tidak akan pernah menjadi salah.


2
2018-02-09 20:06



JavaScript memiliki satu utas dan memiliki satu utas di mana saja.

Saya pikir pertanyaan ini bagus: Apakah JavaScript dijamin akan single-threaded?

Ketika kode Anda dalam loop, ocde lain tidak mengeksekusi dan memblokir.


1
2018-02-10 04:31