Itu pertanyaan yang bagus. Saya ingin mengatakan "ya". Saya tidak bisa.
JavaScript biasanya dianggap memiliki satu utas eksekusi yang terlihat oleh skrip (*), sehingga ketika skrip inline, pendengar acara, atau batas waktu Anda dimasukkan, Anda tetap memegang kendali sepenuhnya sampai Anda kembali dari ujung blok atau fungsi Anda.
(*: mengabaikan pertanyaan apakah browser benar-benar mengimplementasikan mesin JS mereka menggunakan satu OS-thread, atau apakah thread-of-eksekusi terbatas lainnya diperkenalkan oleh WebWorkers.)
Namun, pada kenyataannya ini tidak sepenuhnya benar , dengan cara licik yang jahat.
Kasus yang paling umum adalah kejadian langsung. Peramban akan memecat ini segera ketika kode Anda melakukan sesuatu yang menyebabkannya:
var l= document.getElementById('log');
var i= document.getElementById('inp');
i.onblur= function() {
l.value+= 'blur\n';
};
setTimeout(function() {
l.value+= 'log in\n';
l.focus();
l.value+= 'log out\n';
}, 100);
i.focus();
<textarea id="log" rows="20" cols="40"></textarea>
<input id="inp">
Menghasilkan log in, blur, log out
semua kecuali IE. Peristiwa ini tidak hanya terjadi karena Anda menelepon focus()
langsung, tetapi bisa juga terjadi karena Anda menelepon alert()
, atau membuka jendela sembul, atau apa pun yang menggerakkan fokus.
Ini juga dapat menyebabkan acara lain. Sebagai contoh, tambahkan i.onchange
pendengar dan ketik sesuatu di input sebelum focus()
panggilan tidak fokus, dan urutan log adalah log in, change, blur, log out
, kecuali di Opera di mana itu log in, blur, log out, change
dan IE di mana itu (bahkan kurang jelas) log in, change, log out, blur
.
Demikian pula memanggil click()
elemen yang menyediakannya memanggil onclick
penangan segera di semua browser (setidaknya ini konsisten!).
(Saya menggunakan on...
properti event handler langsung di sini, tetapi hal yang sama terjadi pada addEventListener
dan attachEvent
.)
Ada juga banyak keadaan di mana peristiwa dapat memanas saat kode Anda masuk, meskipun Anda tidak melakukan apa pun untuk memprovokasi. Sebuah contoh:
var l= document.getElementById('log');
document.getElementById('act').onclick= function() {
l.value+= 'alert in\n';
alert('alert!');
l.value+= 'alert out\n';
};
window.onresize= function() {
l.value+= 'resize\n';
};
<textarea id="log" rows="20" cols="40"></textarea>
<button id="act">alert</button>
Tekan alert
dan Anda akan mendapatkan kotak dialog modal. Tidak ada lagi skrip yang dijalankan hingga Anda menolak dialog itu, ya? Nggak. Ubah ukuran jendela utama dan Anda akan mendapatkan alert in, resize, alert out
di textarea.
Anda mungkin berpikir tidak mungkin untuk mengubah ukuran jendela sementara kotak dialog modal naik, tetapi tidak demikian: di Linux, Anda dapat mengubah ukuran jendela sebanyak yang Anda inginkan; pada Windows itu tidak mudah, tetapi Anda bisa melakukannya dengan mengubah resolusi layar dari yang lebih besar ke yang lebih kecil di mana jendela tidak muat, menyebabkan ukurannya kembali.
Anda mungkin berpikir, yah, itu hanya resize
(dan mungkin beberapa lebih seperti scroll
) yang dapat diaktifkan ketika pengguna tidak memiliki interaksi aktif dengan browser karena skrip di-threaded. Dan untuk satu jendela Anda mungkin benar. Tapi itu semua menjadi pot segera setelah Anda melakukan skrip lintas-jendela. Untuk semua browser selain Safari, yang memblokir semua jendela / tab / bingkai ketika salah satu dari mereka sibuk, Anda dapat berinteraksi dengan dokumen dari kode dokumen lain, berjalan di utas terpisah dari eksekusi dan menyebabkan penangan acara terkait untuk api.
Tempat-tempat di mana peristiwa yang Anda dapat hasilkan dapat dimunculkan saat skrip masih berulir:
ketika popup modal ( alert
, confirm
, prompt
) terbuka, di semua browser tapi Opera;
selama showModalDialog
di browser yang mendukungnya;
kotak dialog "Skrip pada halaman ini mungkin sibuk ...", bahkan jika Anda memilih untuk membiarkan skrip terus berjalan, memungkinkan acara seperti mengubah ukuran dan memburamkan dan ditangani bahkan ketika skrip berada di tengah-tengah busy-loop, kecuali di Opera.
beberapa waktu yang lalu bagi saya, di IE dengan Sun Java Plugin, memanggil metode apa pun pada applet dapat memungkinkan acara untuk diaktifkan dan skrip dimasukkan kembali. Ini selalu bug yang sensitif terhadap waktu, dan mungkin Sun telah memperbaikinya sejak itu (saya tentu berharap demikian)
mungkin lebih. Sudah lama sejak saya menguji ini dan browser telah mendapatkan kompleksitas sejak itu.
Singkatnya, JavaScript tampaknya bagi sebagian besar pengguna, sebagian besar waktu, memiliki alur eksekusi tunggal yang ketat berdasarkan peristiwa. Pada kenyataannya, itu tidak memiliki hal seperti itu. Tidak jelas seberapa banyak ini hanyalah bug dan seberapa banyak disengaja desain, tetapi jika Anda menulis aplikasi yang kompleks, terutama yang cross-window / frame-scripting, ada setiap kesempatan itu bisa menggigit Anda - dan secara intermiten, cara sulit untuk debug.
Jika yang terburuk menjadi yang terburuk, Anda dapat memecahkan masalah konkurensi dengan mengarahkan semua respons peristiwa. Ketika suatu peristiwa masuk, letakkan dalam antrian dan urus dengan antrian nanti, dalam suatu setInterval
fungsi. Jika Anda menulis kerangka kerja yang Anda maksudkan untuk digunakan oleh aplikasi yang kompleks, melakukan ini bisa menjadi langkah yang baik. postMessage
semoga juga akan meringankan rasa sakit scripting lintas dokumen di masa depan.