holodepth

Holodepth • Runtime Atlas • Tarayıcı mimarisi · Tier 2

Event Loop Sistemi

JavaScript motoru kodu call stack üzerinde yürütür; event loop ise ana thread’de sıradaki görevi alır, macrotask’ı bitirir, microtask kuyruğunu boşaltır ve gerekirse çizim fırsatı değerlendirir. Bu sayfa, byteomi.com Tarayıcı Mimarisi serisinin canlı karşılığıdır.

Kaynak: byteomi.com · Üç.js gerekmez; saf frontend tracing simülasyonu.

Holodepth köprüsü

byteomi.com · Event Loop Sistemi makalesi call stack, task queue, microtask, rendering sync ve async davranışı metinsel mimari olarak işler. Holodepth bu sayfada aynı sözlüğü tekrar etmez; soruyu çevirir: bir Three.js / WebGL sahnesinde hangi iş hangi sırada ana thread’e oturur ve ekran ne zaman güncellenir?

Sahne mimarisi açısından event loop «arka plandaki tarayıcı detayı» değil, çizim sözleşmesinin zamanlamasıdır. Kamerayı döndüren OrbitControls, mesh’i hareket ettiren AnimationMixer, raycaster ile seçilen obje, GLTF yüklenince sahnaya eklenen model hepsi ya senkron call stack’te, ya bir macrotask / microtask callback’inde, ya da bir sonraki requestAnimationFrame turunda çalışır. Loop’un sırasını bilmeden «neden scroll akıcı ama mesh bir frame gecikmeli?» sorusu spekülasyona döner.

Holodepth Runtime Atlas modeli bu yüzden göz eğitimi verir: Byteomi’de okuduğunuz macrotask → microtask → (gerekirse) rendering fırsatını, burada şerit ve süre blokları olarak görürsünüz. Aşağıdaki bölümler simülatör panelini, Holodepth tracing okumasını ve sahne tarafındaki karşılıkları açıklar; motor sözlüğü için Byteomi kaynağına dönün.

Timeline nasıl okunur?

Aşağıdaki panel, Chrome DevTools Performance veya Apple Instruments timeline’ına benzer okunur fakat Holodepth’te amaç profilör olmak değil: sahnenin nabzını tanımak. Önce bu kuralları gözünüzde canlandırın; ardından simülatöre geçip aynı desenleri arayın. Three.js dünyasında «frame» çoğu zaman renderer.render(scene, camera) ile biter; o çağrı ancak event loop bir rendering opportunity verdiğinde anlamlıdır.

Sahne mimarisinde timeline’ı şöyle okuyun: Main şeridi senkron JS’i (ağır hesap, zorla layout okuma, tek karede yüzlerce mesh güncellemesi); Microtask Promise / await ile gelen asset veya state tepkilerini; rAF animasyon ve kamera güncellemesini; Render stil / layout / paint fırsatını; Compositor ise transform/opacity ile main’i rahatlatan kaydırmayı temsil eder. Bir şerit şiştiğinde soru «hangi API?» değil, «sahnenin hangi katmanı bu frame’i yedi?» olur.

  • Soldaki her satır. En üstte Call stack LIFO derinliğini gösterir (görev kuyruğu değil). Altında main, microtask, input, rAF, render, idle, VSync, compositor ve GC şeritleri vardır. Teşhiste önce hangi şeritte uzama olduğuna bakın sorun stack mi, JS mi, render mı hemen daralır. Sahne örneği: stack platosu + geniş Main → animate() içinde sonsuz senkron döngü veya ağır senkron parse; paint henüz sıraya giremez.
  • Call stack ≠ task queue. Stack şeridi senkron çağrı derinliğidir: kısa JS’te yükselip iner; long task’te plato (turuncu alan) görünür stack boşalmadan loop yeni macrotask alamaz, paint ertelenir. Üzerine gelince depth ipucu açılır. Byteomi’deki call stack sezgisi burada canlıdır; Holodepth’te ek olarak «kamera/mesh güncellemesi bu platonun neresinde?» diye bakarsınız.
  • Zaman soldan sağa akar. Yeni olaylar sağa doğru eklenir; geçmiş sol tarafta kalır. Panelde «Pause» ile dondurup «Timeline scrub» ile geçmiş bir frame’e gidin; o anki blok dizilimini rahatça inceleyin. Sahne debug’ında da aynı refleks: şüpheli kareyi dondur, şeritleri sırayla oku.
  • Her blok bir süre. Birincil sinyal renk + şerit + genişliktir (Chrome Performance ile aynı okuma alışkanlığı). Blok içine yazı basılmaz dar dilimde truncate olmaz; süre ve ad hover / tık tooltip’tedir. Geniş blok yavaş, ince blok hızlı demektir. Geniş Main + boş Render = «JS bitti sandık, piksel henüz yok» hissi.
  • Dikey çizgiler frame sınırı. Her tur VSync’ta ince bir çizgi belirir. drop budget ciddi aşımı, late gecikmiş tur, skip render fırsatının kaçırıldığını işaret eder etiket rengine güvenerek «iyi frame / kötü frame» ayrımı yapın. 60 Hz sahnede hedef ≈16,67 ms; aynı iş 120 Hz’de daha kolay düşer.
  • Arka plan ısısı (frame heat). Turuncu ve kırmızı bantlar o frame’de ana thread’in ne kadar sıkıştığını gösterir. Main thread’de kırmızı glow’lu geniş blok görürseniz long task (>50 ms) vardır; tıklama ve scroll bu frame’de gecikebilir canvas üzerinde raycast / drag da aynı kaderi paylaşır.
  • Üstteki FPS sparkline. Anlık hız eğrisini verir; düşüş veya dalgalanma arayın. Önemli: Sparkline yüksek olsa bile render şeridi boşsa ekran güncellenmiyor olabilir microtask spam ile bu yanıltıcı tabloyu bilinçli test edin. WebGL’de «60 FPS» yazıp sahnenin eski karede kaldığı durumlar buradan okunur.
  • Hover / tık ile öğrenme. İmleci bir bloğa getirin: tam ad, süre ve Türkçe açıklama tooltip’te. Pause iken bloğa tıklayın kart sabitlenir (tekrar tık kaldırır). Dar µtask/click dilimlerinde okuma yolu budur.
  • Phase + DevTools karşılığı + ledger. HUD’daki Phase aktif schedule fazını gösterir; «Frame budget köprüsü» 16.67/8.33 ms limit çizgisini ve 50 ms long-task bayrağını bağlar. Sağdaki SCOPE/LEDGER kuyruk derinliği ve drop/late/skip sayaçlarını özetler Gap Rail tarzı ikinci göz. Frame Budget sayfasında layout/paint/overflow killer stage’e iner.

Event Loop ≠ render pipeline ≠ WebGL pipeline. Bu preset zamanlamayı öğretir: hangi queue render fırsatını geciktirdi? GPU’da vertex / fragment maliyeti ayrı katmandır (WebGL / shader sayfaları). İkisi birbirini besler ama aynı timeline değildir.

  • Call stack LIFO derinlik · senkron foo→bar · plato = boşalmıyor
  • Main thread Long task · sync JS · macrotask callback
  • Microtask Promise chain · queueMicrotask · await devamı
  • Input Pointer/keyboard dispatch · INP öncesi gecikme
  • rAF requestAnimationFrame · paint öncesi hook · Three.js animate
  • Render Rendering opportunity · style→layout→paint sync
  • Idle requestIdleCallback · düşük öncelikli arka plan
  • VSync Display refresh · drop / late / skip işaretleri
  • Compositor Off-main scroll/transform · stale frame riski
  • GC pause Stop-the-world collection · ana thread kesintisi

İlk deneme önerisi: Önce tüm kontroller kapalıyken 10 saniye izleyin; sonra yalnızca Microtask spam açın; mor şeridin uzayıp render’ın kaybolduğunu aynı panelde doğrulayın. Ardından Sakin turPromise önceLong task preset gezisini sahne hikâyesi gibi okuyun.

Event Loop Timeline Simulator

Byteomi runtime · CANLI · Tracing panel

Runtime tracing · ledger (stack · µQ · drop/late/skip) · jitter & burst · rAF · idle · GC · hover / pin tooltips · scrub / pause.

Runtime note Simülasyon gerçek browser scheduling davranışını taklit eder. Timeline bilinçli olarak jitter, burst, delayed frame ve render skip varyasyonu içerir.

REC
Budget remaining 16.7 ms
Frame budget 16.67 ms
Tur süresi
Son JS · LT >50
Display FPS 60
Phase macrotask

Frame budget köprüsü

Kesikli dikey çizgi = bu turdaki 16.67 ms VSync bütçesi. Main’de kırmızı üçgen + bloğun içindeki kesikli çizgi = 50 ms long task eşiği. Render aşamalarının kim yediğini görmek için Atlas’a geç.

eşik 50 ms · görünür 0 LT

Runtime Atlas Frame Budget → layout · paint · overflow · killer stage
DevTools karşılığı Timeline izlerken aktif schedule fazı ve lane referansı burada güncellenir.
Stack LIFO · senkron derinlik
Main Long task · macrotask
Microtask Promise drain
Input Event dispatch
rAF Pre-paint hook
Render Rendering opportunity
Idle requestIdleCallback
VSync Frame boundary
Compositor Off-main path
GC Stop-the-world

;

;

RUNTIME STRESS · PRESET: CALM

Baseline · macrotask → microtasks → rAF → render. Önce bu turu izle.

Önce Sakin tur, sonra tek senaryo seçin (Promise önce → Micro starve → Long task). Slider/toggle elle değişince preset «CUSTOM» olur. Render şeridi içi → Frame Budget.

Bu demo ne işe yarar?

Bu sayfadaki Event Loop Timeline, tarayıcınızdaki gerçek scheduler’a bağlanmaz. Küçük bir öğretim modelidir: «bir frame içinde main thread’de ne sırayla çalışır?» sorusuna görsel cevap verir. Chrome Performance panelinin lane mantığını öğretmek içindir; production profiler değildir. Byteomi makalesinin tablosunu sahne zaman çizelgesine çevirir.

Sahne mimarisi açısından demo şunu sorar: controls.update(), mixer.update(delta), raycaster.intersectObjects ve renderer.render aynı turda nasıl sıralanır? Yatay şeritler Main (macrotask / long task), Microtask (Promise drain örn. GLTF await loader.loadAsync sonrası sahnaya ekleme), Input, rAF (Three.js animate kancası), Render, Idle, VSync, Compositor ve GC’yi temsil eder. 16.7 ms bütçe çizgisi aşılırsa kırmızı overflow; dropped / delayed / skipped işaretleri jitter’ı gösterir. Sağdaki ledger kuyruk derinliği ve drop/late/skip sayaçlarını özetler.

Stres toggle’ları (Heavy JS, Layout thrash, Paint storm, Compositor-only, GC pause) tek tek açıldığında lane’lerin nasıl dolduğunu görürsünüz her biri bir sahne anti-pattern’ine karşılık gelir (ağır senkron tick, DOM/CSS zorlaması, texture/paint baskısı, transform-only scroll, bellek toplama kesintisi). 60 Hz / 120 Hz VSync değişimi bütçe hissini kaydırır. Scrub ile geçmiş frame’lere dönebilir, pause ile dondurabilirsiniz.

Nasıl kullanırsınız? Önce normal akışı izleyin; sonra bir toggle açın ve hangi şeridin şiştiğine bakın. Uzun kırmızı Main bloğu → input gecikmesi hissi (canvas’ta tıklama / sürükleme de gecikir). Compositor-only açıkken main rahat, animasyon yine akıyor; layer promotion sezgisidir ama içerik stale kalabilir. Render detayı için Frame Budget demosuna geçin; teori için Byteomi Event Loop makalesine dönün.

Frame içinde gerçekte ne oluyor?

Simülatör her frame turunda kabaca şu sırayı üretir Byteomi’nin «macrotask › microtask’ları boşalt › (gerekirse) rendering › sonraki macrotask» özetinin canlı hali. Timeline’da bazen adımlar üst üste biner veya jitter ile kayar; gerçek motor da mükemmel hizalı değildir. Aşağıdaki sıra, Holodepth sahnesinde hangi kodun hangi şeride düştüğünü eşleştirmek içindir; V8/JIT veya Blink pipeline dersi değildir.

Tipik bir Three.js döngüsü çoğu zaman tek bir requestAnimationFrame callback’inde toplanır: delta hesapla → kontroller → mixer → fizik adımı → renderer.render. Bu callback macrotask değil, rAF fazıdır; ama callback’in içindeki senkron iş Main/call stack şeridinde görünür. Promise ile yüklenen model sahnaya microtask veya sonraki macrotask’te eklenir «load bitti» ile «ekranda göründü» arasında en az bir rendering opportunity gerekir.

  1. Macrotask çalışır (timer, click, I/O callback). Sahne örneği: pointerup ile seçim, setTimeout ile ertelenmiş spawn, fetch tamamlanınca gelen macrotask callback.
  2. Microtask queue tamamen boşalır Promise / await devamı. Sahne örneği: await loadAsync sonrası scene.add(gltf.scene); zincir uzarsa render fırsatı gecikir (Byteomi’deki starvation ile aynı aile).
  3. requestAnimationFrame callback’i paint öncesine hizalanır; gecikmişse rAF (late) görürsünüz. Burası Holodepth’te animate / controls.update / hafif ölçüm için doğal yerdir ağır layout burada da pahalıdır.
  4. Render fırsatı oluşursa style → layout → paint → composite adımları render şeridine yazılır; budget dolmuşsa render skipped. WebGL draw çağrıları GPU tarafındadır; bu şerit önce «tarayıcı çizim fırsatını verdi mi?» sorusunu cevaplar.
  5. Idle callback (varsa) boş aralıkta kısa süre çalışır düşük öncelikli önbellek, analytics, soğuk asset hazırlığı.
  6. Compositor scroll/transform günceller; layout atlanırsa stale frame mümkündür. CSS transform ile kaydırılan HUD veya canvas wrapper akıcı görünüp içerik eski kalabilir.
  7. VSync frame sınırı drop / late / düzenli tik. Sahnenin «kaç Hz’e oturduğu» burada okunur.

Neden microtask render’ı bloklar? Microtask fazı bitmeden yeni macrotask ve rendering opportunity gelmez. Spam açıkken mor şerit uzar, render şeridi boş kalır; FPS sparkline yüksek olsa bile ekran güncellenmeyebilir. Holodepth sahnesinde bu, «model yüklendi ama canvas bir süre eski karede kaldı» şikâyetinin zamanlama karşılığıdır.

Kontroller ne yapıyor?

Kontroller Byteomi sözlüğünü ezberletmez; her anahtar bir sahne stresini taklit eder. Tek tek açın, hangi şeridin şiştiğine bakın, sonra gerçek ürün şikâyetiyle eşleştirin. Amaç «toggle ne yapıyor?» değil: «sahnemde benzer bir yük varsa timeline’da ne görünür?»

JS load
Main thread’de senkron iş yükünü artırır. Uzun süre → long task glow, kırmızı frame heat, drop / late. Sahne karşılığı: tek karede binlerce matrixWorld zorlaması, senkron JSON parse, canvas’ta ağır raycast döngüsü tıklama ve kamera sürüklemesi gecikir. Karşılık Long task · main thread blocked
Microtask spam
Promise zinciri benzeri ardışık microtask üretir. Render fırsatını geciktirir veya atlar «yüksek FPS, güncellenmeyen ekran» senaryosu. Sahne karşılığı: asset yüklendikten sonra birbirini tetikleyen then zinciri; React/state cascade’in loop dilindeki kuzeni. Karşılık Microtask queue drain · render starvation
Heavy layout
Render şeridinde layout süresini uzatır; frame budget’ı hızla tüketir. Sahne karşılığı: HUD DOM’unu her frame’de ölçmek (getBoundingClientRect), canvas boyutunu sık değiştirmek, CSS ile 3D overlay’i zorlamak WebGL çizimi beklerken ana thread layout’ta kalır. Karşılık Rendering sync · forced reflow (detay: Frame Budget)
Paint storm
Paint + raster bloklarını şişirir; texture upload baskısı turuncu/kırmızı heat. Sahne karşılığı: sık needsUpdate texture, büyük canvas yeniden boyama, DOM + WebGL’in aynı karede yarışması. Karşılık Paint/raster pressure · paint-bound
Compositor-only
Layout/paint atlanır; yalnızca compositor güncellenir. Hızlı scroll hissi içerik stale kalabilir. Sahne karşılığı: CSS transform ile kaydırılan panel veya parallax katman; canvas içeriği bir frame geride kalabilir. Karşılık Compositor thread · transform-only path
GC pause
V8 stop-the-world benzeri kısa duraklama mor GC şeridinde ana thread kesintisi. Sahne karşılığı: kısa ömürlü geometry/material oluşturup atmak, sekme arka plandan dönünce ani takılma. Karşılık GC pause · stop-the-world · jank spike
60 Hz / 120 Hz
Frame budget hedefini değiştirir (≈16,67 ms vs ≈8,33 ms). Aynı JS yükü 120 Hz’de daha kolay drop üretir. Sahne karşılığı: yüksek yenilemeli monitörde aynı tick maliyeti «daha sık bütçe aşımı» olarak hissedilir. Karşılık VSync budget · daha sık frame sınırı

Okuma ipucu: Önce hangi şerit uzadığına bakın (lane), sonra Phase ve DevTools karşılığı hangi queue/fazın suçlu olduğunu söyler. Layout/paint milisaniye ayrımı Frame Budget preset’indedir. Sözlük için Byteomi Event Loop; sahne etkisi için bu panel.

Ne görmelisiniz?

Bu kartlar «doğru / yanlış cevap» değildir; timeline’da aramanız gereken görsel imzalardır. Holodepth sahnesinde sağlıklı runtime, kameranın ve mesh’in her VSync’te güncellendiği, input’un aynı karede yanıt verdiği durumdur. Kötü imza ise kullanıcıya «takıldı / dondu / eski kare» olarak yansır Byteomi’deki long task, starvation ve rendering sync kavramlarının sahne diline çevrilmiş hali.

Sağlıklı runtime

  • Main thread blokları kısa; long task glow yok.
  • Frame heat düşük (soluk arka plan).
  • VSync dikey çizgileri düzenli; çoğunlukla late / drop yok.
  • Render şeridinde ince style/composite; microtask şeridi kısa.
  • Frame budget remaining sürekli birkaç ms üzerinde.

Runtime starvation

  • Microtask (mor) blokları frame boyunca uzar.
  • render skipped veya render şeridi neredeyse boş.
  • FPS sparkline yüksek görünür ama ekran güncellenmez yanıltıcı metrik.
  • VSync’ta skip artar.

Paint / layout overload

  • Render lane’de layout + paint + raster genişler.
  • Frame heat turuncu/kırmızı; late sıklaşır.
  • Budget sayacı sıfıra yakın veya negatif hissi (kırmızı pulse).

Long task / dropped frame

  • Main thread’de geniş kırmızı glow (>50ms).
  • VSync’ta drop etiketi; input/rAF gecikmesi.
  • Scroll/click hissi «takılır» INP kötüleşir; canvas drag/orbit de aynı.

Okuma sırası: önce lane (nerede şişti?), sonra Phase / ledger (hangi sayaç yükseldi?), sonra sahne hipotezi (hangi kod yolu?). GPU fill-rate sorunları bu preset’in dışında kalır; onlar için WebGL / Frame Budget katmanına geçin.

Gerçek hayat karşılığı

Akademik tanımlar sahada his olarak farklı gelir. Aşağıda her senaryoyu ürün deneyimi, timeline deseni ve simülatörde hangi anahtarları açmanız gerektiğiyle eşleştiriyoruz; önce okuyun, sonra panelde aynı deseni arayın. Byteomi «neden donar?» diye sorar; Holodepth «sahnemin hangi şeridi bunu üretir?» diye sorar.

  • Sonsuz feed scroll «jank». Kullanıcı kaydırırken içerik «takılar», görseller geç gelir. Genelde layout + paint baskısı vardır: render şeridinde geniş layout/paint blokları, frame heat turuncuya döner, VSync’ta sık late görürsünüz. Simülatörde Heavy layout ve Paint storm’u birlikte açın; scroll sırasında render lane’in uzadığını izleyin.
  • React / state «infinite rerender». Arayüz güncelleniyor gibi hissedilir ama ekran donuk kalabilir microtask seli ve orta JS yükü render fırsatını yutar. Timeline’da mor microtask şeridi uzar, render skipped veya boş render lane belirir; FPS sparkline yüksek olsa bile güvenmeyin. Deneme: Microtask spam + JS load ~%40–50.
  • Mobil cihaz donması. Dokunma veya scroll’a geç cevap; uygulama «kilitlenmiş» gibi. Ana thread’de uzun kırmızı glow (long task) ve VSync’ta drop tipik. Zayıf cihazda 120 Hz hedefi budget’ı daha da daraltır. Simülatörde JS load’u yükseltin veya 120 Hz seçin; kırmızı glow + drop etiketini birlikte arayın.
  • Parallax / transform-only scroll. Kaydırma akıcı görünür çünkü çoğu hareket compositor’da layout/paint atlanır. Risk: içerik güncellenmeden eski kare (stale frame) gösterilebilir. Yalnızca Compositor-only açın; compositor şeridinde scroll, ara sıra stale işaretini doğrulayın.
  • Tab arka planda GC takılması. Sekme geri gelince kısa takılma veya gecikmeli tepki; V8 GC ana thread’i anlık durdurur. Mor GC şeridinde ince pause + macrotask gecikmesi görülür. GC pause ve orta JS load ile arka plandaki «takılma» hissini timeline üzerinde canlandırın.
  • GLTF / texture yüklenince «bir an donma». Model geldikten sonra sahnaya ekleme, material bağlama ve ilk upload aynı turda sıkışırsa Main veya Microtask şeridi uzar; ilk görünür kare gecikir. Deneme: Promise önce + kısa Long task; load bitince → paint arası boşluğu izleyin.
  • AnimationMixer + OrbitControls aynı rAF’te. İkisi de rAF’e ait; ama mixer + fizik + yüzlerce uniform güncellemesi senkron Main süresini şişirir. rAF şeridi ince kalıp Main’in uzaması tipik Holodepth imzasıdır «animasyon kancası doğru, iş yükü yanlış yerde».

Pratik alıştırma: Bir senaryoyu seçin, ilgili kontrolleri açın, Pause ile dondurun; timeline’daki desen ile kullanıcı şikâyetini yan yana eşleştirin. Teori için Byteomi Event Loop Sistemi makalesine dönün; Holodepth’te amaç aynı kavramları panelde ve sahne dilinde tanımaktır.

Özet ve seriye devam

Bu sayfanın referans iskeleti aynı kaldı: köprü → okuma → canlı model → frame sırası → kontroller → imzalar → gerçek hayat → özet. Byteomi Event Loop Sistemi makalesi call stack / task / microtask / rendering sync sözlüğünü verir; Holodepth aynı sözlüğü sahne mimarisi zamanlamasına bağlar neyin hangi şeritte göründüğünü, neyin FPS’i yanıltabileceğini ve neyin Frame Budget’a taşınacağını gösterir.

Runtime Atlas’ın çekirdeği paylaşılan tracing engine + konu preset’leridir. Event Loop preset’i ana thread zamanlamasını öğretir; sıradaki Atlas demosu Frame Budget (layout / paint / overflow · killer stage), Browser Topology (süreç / thread haritası) ve V8 JIT (derleme ömrü). Byteomi serisinde ardından Bellek Yönetimi gelir GC şeridinin «neden» katmanı oradadır.

Okuma yolu önerisi: (1) Byteomi’de sırayı bir kez okuyun, (2) bu sayfada Sakin → Promise önce → Micro starve → Long task gezisini yapın, (3) kendi sahnenizde şüpheli kareyi DevTools Performance ile aynı lane dilinde doğrulayın. İlgili Holodepth: requestAnimationFrame · Render loop mantığı.