14 min czytania
Closure w JavaScript, czyli jak funkcja może coś pamiętać
Cześć, tu Adrian!
Od 6 lat buduję szybkie, dostępne aplikacje webowe w TypeScript, React i Next.js. Rozumiem, jak pod spodem działa przeglądarka i silnik JavaScript - dlatego moje aplikacje są szybkie i łatwe w utrzymaniu.
Wybierz kategorię.
Posty, które są dobrym punktem startowym
14 min czytania
Closure w JavaScript, czyli jak funkcja może coś pamiętać
14 min czytania
Od HTML do piksela: jak przeglądarka renderuje stronę
23 min czytania
Promises w JavaScript - od callback hell do microtask queue
Tematy z największą liczbą postów
Najświeższe wpisy z bloga
Złudzenie zrozumienia: dlaczego dopiero pisanie pokazuje, co naprawdę wiesz
Czujesz, że rozumiesz closure - dopóki nie usiądziesz, żeby wytłumaczyć go krok po kroku. Wtedy pojawia się dziura. Psychologia poznawcza nazwała to złudzeniem głębi wyjaśnienia: nasze poczucie wiedzy jest systematycznie zawyżone, a widać to dopiero, gdy trzeba odtworzyć mechanizm. O tym, czemu pisanie - a najlepiej zbudowanie działającego dema - jest najlepszym sprawdzianem tego, co naprawdę wiesz.
6 min czytania
Big-O bez matematyki: ile naprawdę kosztuje twój kod
Twój kod działa idealnie na dziesięciu elementach i zacina się na dziesięciu tysiącach - mimo że ani jedna linijka się nie zmieniła. Big-O nie mówi „jak szybko”, tylko „jak koszt rośnie, gdy rośnie ilość danych”. O tym, jak rozpoznać kształt tego wzrostu w zwykłym kodzie frontendowym - i jak zamienić pętlę w pętli na coś, co nie zwalnia przy dużej ilości danych.
9 min czytania
Dlaczego dobre decyzje techniczne przegrywają z biznesem
Najlepsza technicznie decyzja może przegrać, bo przedstawiono ją w niewłaściwy sposób. Biznes nie kupuje „czystego kodu” - kupuje koszt, ryzyko i czas. O tym, jak przełożyć refactor, tech debt i „good enough” na te trzy miary - i kiedy „nie” jest właściwą odpowiedzią.
8 min czytania
Jak odpowiedź pisze się słowo po słowie: streaming po HTTP
Odpowiedź AI pojawia się stopniowo nie przez efekt wizualny, tylko przez streaming: ciało odpowiedzi HTTP jest strumieniem, więc serwer może odsyłać je kawałkami, a przeglądarka pokazywać każdy od razu. Na froncie czyta się to na dwa sposoby - prościutkim EventSource (SSE) albo elastycznym fetch ze strumieniem - i dokładnie tego drugiego używają pod spodem biblioteki do LLM-ów.
7 min czytania
Gdzie żyje cache: ile kopii jednej odpowiedzi istnieje naraz
Ta sama odpowiedź serwera może w jednej chwili leżeć w kilku cache'ach naraz - pamięci aplikacji, Service Workerze, cache HTTP, na CDN - a całą stronę trzyma jeszcze bfcache. Każdy ma innego właściciela i co innego go czyści, więc „wyczyść cache" trafia w jeden z nich, czasem w żaden. Zostaje pytanie, od którego zaczyna się każde takie debugowanie: która warstwa trzyma starą kopię i co ją unieważnia.
9 min czytania
Service Worker - kod, który odpowiada zamiast serwera
Wyłącz internet, odśwież stronę - a ona dalej działa. Stoi za tym Service Worker: osobny skrypt, który wchodzi między stronę a sieć i przechwytuje każde żądanie o plik, zanim trafi ono do serwera. To on decyduje, czy odpowiedzieć z sieci, z własnego cache (Cache API), czy po swojemu - a z tej jednej decyzji biorą się wszystkie strategie cache'owania, tryb offline i klasyczna pułapka 'po wdrożeniu user widzi starą wersję'.
12 min czytania
HTTP caching: czemu druga wizyta na stronie jest natychmiastowa
Weź jeden plik style.css i prześledź jego dzień na działającej stronie: najpierw pobiera go przeglądarka, potem serwuje go z pamięci bez pytania serwera, później pyta serwer, czy jej kopia jest nadal aktualna, i zwykle dostaje samo potwierdzenie zamiast całego pliku, a po wdrożeniu nowej wersji pobiera go od nowa. Z tej jednej historii wychodzi cały HTTP caching - Cache-Control, ETag, 304 i stale-while-revalidate.
9 min czytania
SSR, SSG, ISR, CSR - kiedy powstaje HTML i jakim kosztem
Cztery strategie renderowania nie są wyborem z menu, tylko decyzją per route: gdzie powstaje HTML i kiedy. Każda ma inny moment generacji, inny TTFB, inny koszt infrastruktury i inny stosunek 'świeże dane vs prędkość'. Rozkładam mechanikę czterech podejść i pokazuję, kiedy które ma sens.
20 min czytania
Same-origin policy i CORS, czyli kto może czytać dane z innego serwera
Same-origin policy (SOP) w przeglądarce blokuje kod JavaScript z jednej strony przed czytaniem danych z innej domeny - chyba że serwer wprost pozwoli przez CORS. W poście opisuję, jak działa ten mechanizm zgody serwera i czemu czasem widzisz preflight OPTIONS, a czasem nie.
11 min czytania
Od HTML do piksela: jak przeglądarka renderuje stronę
Każdy element DOM przechodzi przez pięć etapów, zanim go zobaczysz, niezależnie od frameworka. Niektóre style odpalają tylko ostatni etap, inne uruchamiają wszystkie pięć. Stąd różnica w kosztach animacji - od jednego etapu composite po pełny reflow.
14 min czytania
Garbage Collection w JavaScripcie - jak silnik sprząta po twoim kodzie
Każdy obiekt, który tworzysz w JS, zajmuje miejsce w pamięci komputera. JavaScript usuwa nieużywane obiekty automatycznie, robiąc miejsce na nowe. Silnik czasem jednak nie potrafi rozpoznać, że dany obiekt nie jest już potrzebny - i wtedy obiekt zostaje w pamięci. Tak powstają memory leaki. Post o mechanizmie tego sprzątania (mark-and-sweep), o najczęstszych pułapkach i o tym, kiedy faktycznie sięgać po WeakMap czy WeakRef.
14 min czytania
Event Loop w JavaScript - jak silnik decyduje, co odpalić następne
JavaScript ma jeden wątek, ale potrafi czekać na wiele rzeczy równocześnie. Sekret to event loop - prosty algorytm, który wybiera, co odpalić, gdy stack jest pusty. Microtaski wyprzedzają taski, render wpasowuje się między cyklami, a kolejność wykonania zaczyna mieć logiczny sens.
16 min czytania
Słowo kluczowe this w JavaScript - cztery reguły bindingu w jednym miejscu
this w JS zachowuje się dziwnie tylko dlatego, że ludzie patrzą nie tam, gdzie trzeba. Wartość this ustala się dopiero w momencie wywołania funkcji - są tylko cztery reguły, które to wywołanie może wybrać, plus arrow functions, które wyłamują się z całego systemu.
6 min czytania
async/await w JavaScript - jak funkcja może czekać bez blokowania wątku
async/await wygląda jak magia: piszesz await fetch(...), dostajesz wynik w kolejnej linijce, a wątek nie blokuje się ani na moment. Pod spodem nie ma magii - jest stary wzorzec generator + Promise + auto-runner, ukryty pod nowymi słowami async i await.
10 min czytania
Generators w JavaScript - funkcja, która umie się zatrzymać
Zwykła funkcja w JS leci od góry do dołu, zwraca wynik i znika z pamięci. Generator jest inny - oznaczony function*, na każdym yield zatrzymuje swoje wykonanie, oddaje wartość i czeka na kolejne .next(). Mała zmiana w runtime, ale to ona stoi za sekwencjami liczonymi na żądanie i pod spodem async/await.
10 min czytania
Hoisting w JavaScript, czyli o czym tak naprawdę mówi ta metafora
Standardowe tłumaczenie hoistingu mówi, że deklaracje przesuwają się na górę kodu. Specyfikacja ECMA-262 nie definiuje hoistingu jako mechanizmu, a let zachowuje się tak, jakby tej zasady nie znał. Co więc naprawdę dzieje się przed wykonaniem twojego kodu i dlaczego TDZ wygląda dokładnie tak, jak wygląda?
9 min czytania
Execution Context i Call Stack - jak JavaScript wykonuje twój kod
Każda linia JS musi gdzieś się wykonać, każda zmienna gdzieś żyć, każde wywołanie funkcji po sobie wrócić. Silnik trzyma to wszystko w dwóch strukturach - execution context (gdzie aktualnie jestem) i call stack (skąd przyszedłem). To one stoją za closure, this i asynchronicznością.
8 min czytania
new (i this) w JavaScript - co naprawdę robi to słowo kluczowe
Słowo new w JS wygląda na krótkie, ale silnik uruchamia za nim cztery kroki naraz - tworzy pusty obiekt, podpina this, linkuje go do prototype'u funkcji i zwraca cały obiekt z powrotem. Bez new to samo trzeba napisać ręcznie z Object.create.
16 min czytania
Promises w JavaScript - od callback hell do microtask queue
Async w JS bez Promise to callback hell - kod nie ma jak odwoływać się do trwającej operacji, a obsługa błędów siedzi osobno w każdym callbacku. Promise to obietnica wartości, która przyjdzie później - kod układa się płasko, a błędy łapiesz w jednym miejscu.
23 min czytania
Closure w JavaScript, czyli jak funkcja może coś pamiętać
Funkcje w JS zwykle znikają ze swoją lokalną pamięcią. Closure łamie tę regułę - i to na niej opiera się module pattern, memoizacja, asynchroniczny JS i prywatny stan bez klas.
14 min czytania