İçeriğe geç

JavaScript Olay Döngüsü — setTimeout(0) Neden Sonra Yazıyor?

Başlangıç 9 dk Çok sık karşılaşılır

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.

  1. Bayt: setTimeout'a 0 milisaniye verdim. Yani hemen çalışacak, değil mi?

  2. Sen: Kulağa öyle geliyor.

  3. Bayt: Ama Promise'in then'i ondan önce yazdı! Sıfırdan daha hızlı ne olabilir?

  4. 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.

Hızlı kontrolBaşlangıç

JavaScript bir sayfada aynı anda kaç parça JavaScript kodu çalıştırır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Bir buton tıklandı ama o sırada 3 saniyelik senkron bir döngü çalışıyor. Tıklama callback'i ne zaman çalışır?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

İ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).

Önce elindeki iş, sonra bütün notlar, sonra tek bir müşteri.
Adım adım oku
  1. Aşçı elindeki senkron kodu bitirir.
  2. Yığın boşalınca kapıdaki bütün mikro görevler sırayla yapılır.
  3. Ancak sonra makro görev kuyruğundan bir tane alınır.
  4. 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.

Hızlı kontrolBaşlangıç

Hangisi mikro görev kuyruğuna girer?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Yığın boşaldı. Mikro kuyrukta iki iş, makro kuyrukta iki iş var. Sırada ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

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.

Hızlı kontrolOrta

async function f() { console.log('1'); await null; console.log('2'); } console.log('0'); f(); console.log('3'); Çıktı nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Konsol hangi sırayla yazar?

Tohum 449068
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');

Çağrı yığını

  1. script

Mikro görevler

boş

Makro görevler

boş

Konsol: …
Hız
Adım 0

Ş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.

  1. İlk programı adım adım oynat. B, setTimeout’a 0 verilmesine rağmen en sona kaldı.
  2. “async fonksiyon ve await” seç. 2, 3’ten sonra yazdı: await fonksiyonu ikiye böldü.
  3. “Zamanlayıcının içinde Promise” seç. T1’in içindeki P2, T2’den önce yazdı.
  4. “Zincirlenen then” seç. Üç then’in hepsi zamanlayıcıdan önce bitti.
Hızlı kontrolOrta

setTimeout içinde (T1) bir Promise.then (P2) kuruluyor; ayrıca ikinci bir setTimeout (T2) var. T1, P2 ve T2 hangi sırayla yazar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

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.

Hızlı kontrolOrta

Kendini sürekli yeniden then ile kuyruğa koyan bir zincir yazıldı. Sayfaya ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

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
Proje dosyaları

src/features/statement/ loadStatement.ts Ekstre yükleyici: await ile her adım bir öncekini bekliyor.

src/features/statement/loadStatement.ts
// Each step waits for the one before it; nothing runs out of order.
export async function loadStatement(api: StatementApi, accountId: string): Promise<Statement> {
const account = await api.account(accountId);
const lines = await api.lines(accountId, account.currentPeriod);
return { account, lines };
}

src/features/statement/ exportCsv.ts Büyük CSV dışa aktarımı parçalara bölünüyor; her parçadan sonra tarayıcıya nefes aldırılıyor.

src/features/statement/exportCsv.ts
// Building a 50 000-line CSV in one loop would hold the call stack and freeze
// the page. A macrotask between chunks lets clicks and painting through.
const yieldToBrowser = (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 0));
export async function exportCsv(lines: readonly StatementLine[], chunk = 2_000): Promise<string> {
const parts: string[] = [];
for (let i = 0; i < lines.length; i += chunk) {
parts.push(lines.slice(i, i + chunk).map(toCsvRow).join('\n'));
await yieldToBrowser(); // a then() here would NOT help: microtasks run before painting
}
return parts.join('\n');
}

src/features/statement/ order.test.ts Test: sıranın gerçekten A D C B olduğunu kanıtlayan küçük bir Vitest.

src/features/statement/order.test.ts
import { expect, it } from 'vitest';
it('runs sync code, then microtasks, then timers', async () => {
const seen: string[] = [];
seen.push('A');
setTimeout(() => seen.push('B'), 0);
Promise.resolve().then(() => seen.push('C'));
seen.push('D');
await new Promise((resolve) => setTimeout(resolve, 0));
expect(seen).toEqual(['A', 'D', 'C', 'B']);
});

Kendini sına

Şimşek turu1/4

setTimeout(fn, 0), fn'i hemen o satırda çalıştırır.

Soru 1/3Orta

setTimeout(fn, 0) en doğru nasıl okunur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 1 JavaScript bir anda tek bir iş yapar. Senkron kod her zaman sonuna kadar çalışır; araya hiçbir callback giremez.
  2. 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. 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.
Sonraki kapı Sayacı artırdın, ekran güncellendi, ama konsoldaki değer hâlâ eskisi. Nasıl? React Render Modeli · 10 dk

5 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı

Bu dersin üstüne kurulanlar

Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.