مدیر محصولام
پشتپرده رندرینگ مرورگر از صفر تا یک
چطور یه صفحه وب زنده میشه؟ یه داستان واقعی از دل مرورگر!
خب، یه لحظه تصور کن داری یه آدرس وب تو مرورگرت تایپ میکنی و Enter رو میزنی. انگار داری یه جادوی دیجیتال رو شروع میکنی! یه لحظه بعد، صفحه وب مثل یه نقاشی زنده جلوی چشمت ظاهر میشه. اما پشت این جادو، یه داستان پرهیجان و پیچیده جریان داره که انگار یه فیلم اکشنه، پر از قهرمانهای خاموش مثل DOM، CSSOM و Render Tree که با هم کار میکنن تا این شاهکار رو خلق کنن. آمادهای که پرده رو کنار بزنیم و ببینیم این داستان چطور رقم میخوره؟
داستان رندرینگ: از URL تا صفحهای که عاشقش میشی
بیا با هم قدم به قدم این ماجرا رو کشف کنیم. من قراره این داستان رو اول به زبون ساده تعریف کنم، انگار داریم دور آتیش قصه میگیم. بعدش، میریم تو عمق ماجرا با جزئیات فنی که انگار داریم نقشه گنج رو باز میکنیم. اینجوری چه تازهکار باشی چه حرفهای، یه چیزی گیرت میاد که بتونی باهاش پز بدی!
قدم اول: Navigation and Resource Fetching | پیدا کردن گنج دیجیتال
قصه ساده:
تصور کن مرورگرت یه کارآگاهه که باید سرنخ پیدا کنه. اول میره دنبال آدرس سرور (مثل پیدا کردن خونه یکی تو یه شهر غریب). وقتی پیداش کرد، در میزنه و میگه: «هی، فایل HTML رو بده!» سرور هم مثل یه میزبان خوب، فایل رو میفرسته و ماجرا شروع میشه.
جزئیات فنی:
اینجا انگار مرورگر داره یه عملیات مخفی انجام میده:
- مرحله DNS Resolution: مثل اینه که کارآگاهمون داره تو دفترچه تلفنش دنبال شماره میگرده. مرورگر URL رو به IP تبدیل میکنه. اگه تو کش باشه، زودی پیداش میکنه، وگرنه باید بره سراغ DNS سرورها.
- مرحله TCP Connection: حالا نوبت یه دستدادن دیجیتاله. مرورگر و سرور یه اتصال TCP میسازن، و اگه HTTPS باشه، یه لایه TLS هم اضافه میشه که انگار دارن رمز مخفی رد و بدل میکنن.
- مرحله HTTP Request: مرورگر یه درخواست HTTP GET میفرسته، مثل اینه که بگه: «فایل HTML رو بده، عجله دارم!» سرور جواب میده و HTML مثل یه نامه عاشقانه میرسه.
- مرحله بهینهسازی: برای اینکه کارآگاهمون سریعتر عمل کنه، میتونه از DNS prefetching استفاده کنه یا با HTTP/2 چندتا درخواست رو همزمان بفرسته. انگار چندتا کارآگاه دیگه هم استخدام کرده!
قدم دوم: Parsing HTML (Building the DOM) | ساختن اسکلت داستان
قصه ساده:
حالا که HTML به دستمون رسیده، مرورگر مثل یه معمار شروع میکنه به ساختن یه نقشه درختی به اسم DOM. انگار داره یه خونه میسازه، هر تگ HTML یه آجره که جاشو تو این درخت پیدا میکنه. اگه یه تگ CSS یا JavaScript ببینه، میره دنبالشون، مثل این که وسط ساخت خونه بفهمی نیاز به یه لوستر داری!
جزئیات فنی:
اینجا ماجرا یه کم پیچیدهتر میشه:
- مرحله Tokenization: مرورگر HTML رو میگیره و مثل یه کدشکن، تگها، ویژگیها و متنها رو جدا میکنه. حتی اگه HTML یه کم بههمریخته باشه، بازم درستش میکنه (مثل یه مادر مهربون که اتاق بههمریخته بچهشو مرتب میکنه).
- مرحله Building the DOM: از این توکنها، یه درخت DOM ساخته میشه، که انگار اسکلت کل صفحهست. هر گره تو این درخت یه عنصر یا متن خاصه.
- مرحله External Resources: اگه وسط کار تگ <link> یا پیدا بشه، مرورگر میره دنبالشون. CSS render-blockingه، یعنی تا بارگذاریش تموم نشه، کار جلو نمیره. JavaScript هم اگه async یا defer نداشته باشه، همهچیزو نگه میداره تا اجرا بشه.
- مرحله بهینهسازی: برای اینکه این مرحله تندتر بره، میتونی DOM رو سبک نگه داری یا از server-side rendering استفاده کنی که انگار یه بخشی از خونه رو آماده تحویل دادن!
قدم سوم: Parsing CSS (Building the CSSOM) | رنگ و لعاب دادن به خونه
قصه ساده:
حالا نوبت اینه که خونهمون رو خوشگل کنیم. مرورگر CSS رو میخونه و یه نقشه استایل به اسم CSSOM درست میکنه. این نقشه میگه هر چیزی چه رنگی باشه، چطور چیده بشه، و چه شکلی به نظر بیاد. تا این کار تموم نشه، صفحه نمیتونه نمایش داده بشه، چون هیچکس نمیخواد یه خونه بدون دکوراسیون ببینه!
جزئیات فنی:
اینجا انگار داریم یه کتاب قانون استایل مینویسیم:
- مرحله CSS Tokenization: CSS به قطعات ریز مثل selectorها، propertyها و valueها شکسته میشه.
- مرحله Building the CSSOM: این قطعات یه درخت CSSOM تشکیل میدن که مشخص میکنه کدوم استایل به کدوم عنصر DOM میچسبه. این شامل مدیریت cascade (مثل اینه که قانون مهمتر برنده میشه) و specificity (مثل یه مسابقه که selector دقیقتر امتیاز بیشتری میگیره).
- مرحله Render-Blocking: چون CSSOM برای رندر لازمه، مرورگر منتظر میمونه تا کامل بشه، وگرنه ممکنه Flash of Unstyled Content (FOUC) پیش بیاد که انگار یکی با لباس زیر تو مهمونی پیداش بشه!
- مرحله بهینهسازی: میتونی critical CSS رو inline کنی تا سریعتر رندر بشه، یا از ابزارهایی مثل CSSNano استفاده کنی که انگار یه کمد شلوغ رو مرتب کردی.
قدم چهارم: Constructing the Render Tree | آماده کردن صحنه نمایش
قصه ساده:
حالا که اسکلت (DOM) و دکوراسیون (CSSOM) آمادهست، مرورگر این دو تا رو قاطی میکنه تا ببینه چی قراره تو صفحه نمایش داده بشه. به این میگن Render Tree، که فقط چیزایی که دیده میشن رو نگه میداره. مثلاً اگه یه چیزی display: none باشه، انگار اصلاً دعوت نشده به این مهمونی!
جزئیات فنی:
اینجا انگار داریم یه فیلمنامه نهایی مینویسیم:
- مرحله Combining DOM and CSSOM: مرورگر DOM و CSSOM رو میگیره و Render Tree رو میسازه، که فقط شامل عناصر قابل مشاهدهست (مثل div، p، یا span که display: none نیستن).
- مرحله Style Calculation: برای هر گره، استایل نهایی محاسبه میشه، با در نظر گرفتن inheritance (مثل ارث بردن رنگ چشم از بابا) و media queries (مثل این که لباس مناسب فصل بپوشی).
- مرحله Edge Cases: اگه JavaScript وسط کار DOM یا CSSOM رو تغییر بده، Render Tree باید آپدیت بشه، که انگار وسط فیلم یه بازیگر جدید اضافه شده!
- مرحله بهینهسازی: از selectorهای ساده استفاده کن و تعداد قوانین CSS رو کم کن تا این مرحله مثل یه نسیم ملایم بگذره.
قدم پنجم: Layout (Reflow) | چیدن میز و صندلیها
قصه ساده:
حالا که میدونیم چی باید نمایش داده بشه، مرورگر باید بفهمه هر چیزی کجا میره و چقدر جا میگیره. به این میگن layout، مثل اینه که داری یه مهمونی رو پلن میکنی و باید مطمئن بشی همه راحت جا میشن.
جزئیات فنی:
اینجا انگار داریم یه نقشه مهندسی میکشیم:
- مرحله Box Model Calculation: برای هر گره تو Render Tree، مرورگر width، height، margin، padding و border رو محاسبه میکنه، مثل این که داره اندازه هر مبل و میز رو چک میکنه.
- مرحله Positioning: موقعیتها نسبت به viewport یا والد (مثل position: absolute یا relative) تعیین میشن.
- مرحله Complex Layouts: چیزایی مثل flexbox یا grid یه کم کارو سختتر میکنن، مثل این که بخوای یه پازل سهبعدی حل کنی.
- مرحله بهینهسازی: برای اینکه layout سریعتر باشه، از will-change برای عناصر متحرک استفاده کن و DOM reads/writes رو دستهبندی کن تا از layout thrashing (مثل قاطی کردن جای مهمونا وسط مهمونی) جلوگیری بشه.
قدم ششم: Painting | رنگ زدن دیوارها و آویزون کردن تابلوها
قصه ساده:
حالا نوبت اینه که خونهمونو رنگ کنیم و تابلوها رو آویزون کنیم. مرورگر هر چیزی که تو Render Tree هست رو به پیکسل تبدیل میکنه و روی صفحه میکشه. این مرحله paintingه، مثل اینه که نقاش اومده و داره شاهکارشو خلق میکنه.
جزئیات فنی:
اینجا انگار داریم یه بوم دیجیتال رنگ میکنیم:
- مرحله Rasterization: هر گره به پیکسل تبدیل میشه، شامل متن، رنگ پسزمینه، border، shadow و تصویر.
- مرحله Layers: مرورگر ممکنه محتوا رو به لایهها تقسیم کنه (مثل عناصری که transform یا opacity دارن) تا بعداً راحتتر آپدیت بشن، انگار نقاشیهای جداگونهای داریم که میتونیم جابجاشون کنیم.
- مرحله GPU Acceleration: بیشتر اوقات، painting به GPU واگذار میشه تا سریعتر و روانتر باشه، مثل این که یه نقاش حرفهای استخدام کردیم.
- مرحله بهینهسازی: برای کم کردن فشار روی نقاش، از CSS سادهتر استفاده کن، مثلاً shadowهای سنگین رو کم کن یا از content-visibility: auto برای چیزایی که فعلاً دیده نمیشن استفاده کن.
قدم هفتم: Compositing | جمع کردن همهچیز برای نمایش بزرگ
قصه ساده:
حالا که همهچیز رنگ شده، مرورگر لایههای مختلف رو مثل یه کارگردان فیلم کنار هم میذاره تا تصویر نهایی رو بسازن. به این میگن compositing، مثل اینه که همه بازیگرای فیلم رو تو یه صحنه جمع کردی و گفتی: «اکشن!»
جزئیات فنی:
اینجا انگار داریم یه فیلم نهایی رو مونتاژ میکنیم:
- مرحله Layer Composition: لایههای painted با هم ترکیب میشن تا تصویر نهایی ساخته بشه. این کار معمولاً تو GPU انجام میشه، که مثل یه استودیوی تدوین پیشرفتهست.
- مرحله Efficiency: چون فقط لایههای تغییرکرده آپدیت میشن، چیزایی مثل اسکرول یا انیمیشن خیلی روان اجرا میشن، انگار فقط یه تیکه از پازل رو عوض کردیم.
- مرحله Edge Cases: اگه تعداد لایهها خیلی زیاد بشه، GPU ممکنه کم بیاره، مثل این که کارگردان بخواد صدتا بازیگر رو تو یه صحنه جا بده!
- مرحله بهینهسازی: فقط عناصری که واقعاً نیاز به لایه دارن رو ارتقا بده (مثل will-change: transform) و از Chrome DevTools Layers panel برای چک کردن استفاده کن.
قدم هشتم: Interactivity (JavaScript Execution and Event Handling) | زنده کردن مهمونی
قصه ساده:
حالا که خونه آمادهست و مهمونی شروع شده، نوبت اینه که بذاریم مهمونا (کاربرا) برقصن! JavaScript مثل DJ مهمونی عمل میکنه، کاری میکنه که وقتی رو دکمهها کلیک میکنی یا اسکرول میکنی، اتفاقای باحال بیفته.
جزئیات فنی:
اینجا انگار داریم یه سیستم کنترلی برای مهمونی راه میندازیم:
- مرحله JavaScript Execution: اگه تگ باشه، مرورگر اسکریپت رو اجرا میکنه. اگه async یا defer نداشته باشه، parser-blockingه و همهچیزو نگه میداره، مثل این که DJ وسط مهمونی غیبش بزنه.
- مرحله Event Loop: بعد از رندر اولیه، مرورگر وارد یه حلقه رویداد میشه که به کلیکها، اسکرولها و تایپها گوش میده و JavaScript رو برای مدیریتشون صدا میکنه.
- مرحله DOM Changes: اگه JavaScript DOM یا CSSOM رو تغییر بده، ممکنه reflow یا repaint راه بیفته، مثل این که وسط مهمونی یکی بخواد مبلا رو جابجا کنه.
- مرحله بهینهسازی: اسکریپتهای غیرضروری رو با defer بنداز عقب، از web workers برای کارای سنگین استفاده کن، و event listenerها رو debounce کن تا مهمونی روان بمونه.
یه کم داستانهای حاشیهای: چیزایی که نباید غافل شی
این داستان فقط به این ۸ مرحله ختم نمیشه. یه سری ماجراهای دیگه هم هست که باعث میشه این نمایش بهتر اجرا بشه:
- معیارهای مهم:
First Contentful Paint (FCP): وقتی اولین چیزی تو صفحه دیده میشه، مثل اینه که پرده تئاتر یه کم باز شده.
Largest Contentful Paint (LCP): وقتی بخش اصلی صفحه لود میشه، انگار ستاره اصلی نمایش رو صحنه اومده.
Time to Interactive (TTI): وقتی صفحه آمادهست که بتونی باهاش بازی کنی، مثل این که مهمونی به اوجش رسیده.
ترفند: با code splitting، lazy-loading و inlining critical CSS میتونی اینا رو تندتر کنی. - رندرینگ پیشرونده: مرورگر مثل یه نقاش باحال، هر چی آماده باشه رو نشون میده، حتی اگه هنوز همهچیز کامل نشده باشه. با skeleton screens میتونی کاری کنی که کاربرا حوصلهشون سر نره.
- حقههای مرورگرهای مدرن:
Speculative Parsing: مرورگر یه جورایی پیشبینی میکنه و قبل از اینکه اسکریپتها آماده بشن، کارشو شروع میکنه، مثل یه دستیار باهوش.
Preload Scanner: لینکهای منابع رو زودی پیدا میکنه و بارگیریشون میکنه، انگار یه تیم پیشقراول فرستاده. - رسانه و فونتها: تصاویر اگه width و height نداشته باشن، ممکنه layout shift راه بندازن، مثل این که وسط مهمونی یکی میزو تکون بده. فونتها هم اگه دیر لود بشن، باعث Flash of Unstyled Text (FOUT) یا Flash of Invisible Text (FOIT) میشن، که انگار خواننده اصلی گروه دیر به صحنه رسیده. با font-display: swap میتونی اینو درست کنی.
- دسترسیپذیری و موقعیتهای خاص:
شبکههای کند نیاز به progressive enhancement دارن، مثل این که مهمونی رو حتی اگه برق بره ادامه بدی.
دستگاههای ضعیف نمیتونن انیمیشنهای سنگین رو تحمل کنن، پس باید سادهتر کار کنی.
برای دسترسیپذیری، از ARIA attributes و HTML معنایی استفاده کن تا همه بتونن تو مهمونی شرکت کنن.
چرا این داستان مهمه؟
این قصه فقط یه مشت اصطلاح فنی نیست. این ماجرا درباره اینه که چطور میتونی یه تجربه بسازی که کاربرا عاشقش بشن. اگه این مراحل رو خوب بفهمی، میتونی صفحهای بسازی که سریع لود بشه، روان کار کنه، و حتی تو بدترین شبکهها هم کاربرا رو ناامید نکنه. شرکتهای بزرگ مثل Snap، Tapsi یا Digikala این چیزا رو تو مصاحبههاشون میپرسن، چون میخوان بدونن تو میتونی یه محصول بسازی که هم خوشگل باشه هم کارآمد.
پایان داستان (ولی نه واقعاً!)
فرآیند رندرینگ مرورگر مثل یه نمایش بزرگه که هر مرحلهاش یه نقش کلیدی داره. از پیدا کردن سرور تا زدن رنگ و لعاب نهایی و زنده کردن صفحه با JavaScript، هر قدم یه تیکه از این پازله. حالا که این داستانو شنیدی، دفعه بعد که یه صفحه وب رو باز میکنی، یه لحظه به این فکر کن که چه ماجراجویی عظیمی پشتش جریان داشته. اگه دوست داری بیشتر تو این دنیای دیجیتال غرق شی، یه سر به MDN Web Docs: How browsers work بزن و خودتو غرق این قصه کن!
موردی بود بگو بهم تو کامنتا، باهم گپ بزنیم در موردش!
مطلبی دیگر از این انتشارات
چطور کامپوننت ها و اجزای دیزاین سیستم ها را حرفهای مستندسازی و داکیومنت کنیم؟
مطلبی دیگر از این انتشارات
نحوه رسیدگی به برقراری ارتباط با API های متعدد توسط Kotlin Coroutine
مطلبی دیگر از این انتشارات
6 چیز که قبل شروع پایتون (Python) باید بدانید