JavaScript Olay Döngüsü — setTimeout(0) Neden Sonra Yazıyor?
30 saniyede özet
JavaScript tek bir aşçıyla çalışan bir mutfak: elindeki işi bitirir, sonra kapıdaki acil notların hepsini, en son sıradaki müşteriyi. Promise ve await notlara, setTimeout sıraya girer. Konsolun sırası buradan gelir.
Bir kafede tek bir aşçı var. Elindeki tabağı bitirmeden başka işe bakmıyor. Bitirince önce kapıya iliştirilmiş acil notlara, sonra sıradaki müşteriye geçiyor.
-
Bayt: setTimeout'a 0 milisaniye verdim. Yani hemen çalışacak, değil mi?
-
Sen: Kulağa öyle geliyor.
-
Bayt: Ama Promise'in then'i ondan önce yazdı! Sıfırdan daha hızlı ne olabilir?
-
Bayt: Hız değil, sıra meselesi. Hangi kuyruğa girdiğine bakalım.
Tek aşçı, tek iş
JavaScript kodu tek bir call stackŞu an çalışan fonksiyonların üst üste dizildiği yığın. JavaScript'te tektir; yığın boşalmadan hiçbir callback çalışmaz.Sözlükte gör → üzerinde çalışır. Bir fonksiyon çalışırken başka hiçbir JavaScript kodu araya giremez.
Bir tıklama, bir zamanlayıcı ya da bir ağ cevabı geldiğinde, callback’i hemen çalışmaz. Bir kuyruğa girer ve yığının boşalmasını bekler.
Kafam karıştı, daha basit anlat
Aşçı tabağı bitirmeden başka işe bakmaz. Gelen her yeni iş kuyrukta bekler.
JavaScript bir sayfada aynı anda kaç parça JavaScript kodu çalıştırır?
Bir buton tıklandı ama o sırada 3 saniyelik senkron bir döngü çalışıyor. Tıklama callback'i ne zaman çalışır?
İki ayrı kuyruk
Sırayla: A'yı yazdır; 0 ms'lik bir setTimeout içinde B'yi yazdır; Promise.resolve().then içinde C'yi yazdır; D'yi yazdır. Konsol hangi sırayla yazar? Cevabı göster
A D C B. Önce senkron kod biter: A ve D. Sonra mikro görevler (C), en son zamanlayıcı (B).
Adım adım oku
- Aşçı elindeki senkron kodu bitirir.
- Yığın boşalınca kapıdaki bütün mikro görevler sırayla yapılır.
- Ancak sonra makro görev kuyruğundan bir tane alınır.
- setTimeout(0) sıraya girer; mikro görevlerin önüne geçmez.
then, await’ten sonraki satırlar ve queueMicrotask bir microtaskPromise.then, await sonrası ve queueMicrotask işleri. Yığın her boşaldığında bu kuyruk tamamen boşaltılır; makro görevlerden önce gelir.Sözlükte gör → olur. Yığın her boşaldığında bu kuyruk tamamen boşaltılır.
setTimeout, tıklamalar ve ağ olayları ise bir macrotasksetTimeout, setInterval, tıklama ve ağ olayları gibi görevler. Mikro kuyruk boşken turda yalnızca bir tanesi çalışır.Sözlükte gör → olur. Her turda yalnızca bir tanesi çalışır, o da mikro kuyruk boşken.
Kafam karıştı, daha basit anlat
Notlar müşteriden önce gelir, hem de hepsi. setTimeout bir müşteridir, then bir nottur.
Hangisi mikro görev kuyruğuna girer?
Yığın boşaldı. Mikro kuyrukta iki iş, makro kuyrukta iki iş var. Sırada ne olur?
await fonksiyonu ikiye böler
async bir fonksiyon, ilk await’e kadar tıpkı normal bir fonksiyon gibi hemen çalışır. await’ten sonraki kısım ise bir mikro görev olarak sonraya kalır.
Bu yüzden await’ten sonra yazdığın satır, fonksiyonu çağıran koddaki sonraki satırdan sonra çalışır. Kod yukarıdan aşağı okunur ama aşağıdan yukarı gibi davranabilir.
Kafam karıştı, daha basit anlat
await, fonksiyonu iki parçaya ayırır: ilk parça şimdi, ikinci parça bir not olarak sonra.
async function f() { console.log('1'); await null; console.log('2'); } console.log('0'); f(); console.log('3'); Çıktı nedir?
Kendin gör
Konsol hangi sırayla yazar?
Tohum 449068console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');Çağrı yığını
- script
Mikro görevler
boş
Makro görevler
boş
Şu an ne oldu?
log, setTimeout, then, log
Önce tahmin et: konsol hangi sırayla yazacak? Sonra adım adım ilerle.
Görevler0/3
setTimeout(0)'ın Promise'ten sonra yazdığını göraçık
İpucu
İlk programı sonuna kadar oynat.
await'in fonksiyonu ikiye böldüğünü göraçık
İpucu
"2" neden "3"ten sonra?
Üç halkalı then zincirinin zamanlayıcıyı geçtiğini göraçık
İpucu
Mikro kuyruk tamamen boşalmadan makro görev başlamaz.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- İlk programı adım adım oynat. B, setTimeout’a 0 verilmesine rağmen en sona kaldı.
- “async fonksiyon ve await” seç. 2, 3’ten sonra yazdı: await fonksiyonu ikiye böldü.
- “Zamanlayıcının içinde Promise” seç. T1’in içindeki P2, T2’den önce yazdı.
- “Zincirlenen then” seç. Üç then’in hepsi zamanlayıcıdan önce bitti.
setTimeout içinde (T1) bir Promise.then (P2) kuruluyor; ayrıca ikinci bir setTimeout (T2) var. T1, P2 ve T2 hangi sırayla yazar?
Tuzaklar
Bitmeyen mikro görevler. Kendini sürekli yeniden kuyruğa koyan bir then zinciri, makro görevlere ve ekranın yeniden çizilmesine hiç sıra bırakmaz. Sayfa donar.
Uzun senkron döngü. Yığını uzun süre meşgul eden bir döngü, tıklamaları da bekletir. Büyük işi parçalara bölmek ya da bir Web Worker’a vermek gerekir.
await’siz async çağrı. save() bir Promise döndürür. Başına await yazmazsan sonraki satır kayıt bitmeden çalışır.
Kafam karıştı, daha basit anlat
Aşçıyı ne bitmeyen notlarla ne de bitmeyen bir tabakla meşgul et. Beklenmesi gereken işin başına await koy.
Kendini sürekli yeniden then ile kuyruğa koyan bir zincir yazıldı. Sayfaya ne olur?
Aşağıdaki örnek bir bankacılık uygulamasının hesap ekranından: işlem listesi yüklenirken ekranın donmaması ve sıranın bilinçli kurulması.
Derinleş · Hesap ekranı: sırayı bilerek kurmak 3 dosya · ~30 satır · ilk okumada atlayabilirsin
Kendini sına
setTimeout(fn, 0), fn'i hemen o satırda çalıştırır.
setTimeout(fn, 0) en doğru nasıl okunur?
Aklında kalacak üç şey
- 1 JavaScript bir anda tek bir iş yapar. Senkron kod her zaman sonuna kadar çalışır; araya hiçbir callback giremez.
- 2 Promise.then, await sonrası ve queueMicrotask mikro görev kuyruğuna girer. Bu kuyruk, her görevden sonra tamamen boşaltılır.
- 3 setTimeout makro görev kuyruğuna girer ve mikro görevler bitince, turda yalnızca bir tane çalışır. setTimeout(…, 0) 'hemen' değil, 'sıraya gir' demektir.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.
- Frontend & EntegrasyonTarayıcı Nasıl Çizer — Animasyon Neden Takılıyor?Kartı left ile kaydırınca takılıyor, transform ile kaydırınca akıyor. Aradaki fark hangi adımda?Derse git
- Frontend & EntegrasyonForm Gönderimi — Bir Tıkla İki Havale Nasıl Olur?Kullanıcı Gönder'e bir kez bastı. Ekstresinde aynı havale iki kez görünüyor. Nasıl?Derse git
- Frontend & EntegrasyonCanlı Veri — Polling, SSE ve WebSocketEkran canlı güncellensin istiyorsun. Her iki saniyede bir sormak neden kötü bir fikir?Derse git