المستوى: مبتدئ — مناسب لو لسه بادئ في تحسين أداء صفحات الويب، والمقال بيشرح كل مصطلح بمثال قبل التعريف العلمي.
في نهاية المقال هتعرف تنقل سطر <script> واحد وتخلّي صفحتك تظهر للمستخدم أسرع بحوالي الثلثين، من غير ما تلمس أي كود جافاسكريبت جوّه الملف. ده أرخص تحسين ممكن تعمله لأداء موقعك.
المشكلة باختصار
لو موقعك بيفضل شاشة بيضا ثانيتين أو تلاتة قبل ما يظهر أي حاجة، وانت متأكد إن السيرفر سريع، المشكلة غالبًا مش في السيرفر. المشكلة إن المتصفح وصل لوسم <script> في الـ <head>، ووقف كل حاجة عشان ينزّل الملف ده ويشغّله. ركّز في الكلمة دي: وقف. الصفحة كلها مستنية سطر واحد.
مثال بسيط قبل الكلام التقني
تخيّل مطعم فيه طباخ واحد وطابور زباين. الطباخ بيمشي بالترتيب: يعمل طلب، يسلّمه، يبدأ اللي بعده. كل حاجة ماشية.
فجأة جه طلب معقّد: كيكة محتاجة تتخبز 20 دقيقة. الطباخ وقف الطابور كله، فضل قدام الفرن 20 دقيقة، وكل الزباين اللي وراه استنّوا من غير أي سبب. الأكل السريع كان جاهز، بس محدش أخده لأن الطباخ مشغول بالكيكة.
المتصفح بيعمل نفس الغلطة. الطابور هو محتوى صفحتك (النصوص، الصور، الأزرار). الكيكة هي ملف الجافاسكريبت. أول ما المتصفح يوصله وهو بيقرأ الصفحة، بيوقف يخبز الكيكة، والمستخدم بيبصّ في شاشة فاضية.
ليه ده بيحصل علميًا
المتصفح بيقرأ ملف الـ HTML من فوق لتحت، سطر سطر، وبيبني منه شجرة اسمها DOM. العملية دي اسمها parsing (التحليل).
لما الـ parser يوصل لوسم <script> عادي (من غير أي خاصية)، بيحصل تلات حاجات بالترتيب:
- الـ parser بيقف تمامًا عن قراءة باقي الصفحة.
- المتصفح ينزّل ملف السكربت من الشبكة (ممكن ياخد وقت طويل على موبايل بشبكة ضعيفة).
- المتصفح يشغّل السكربت، وبعدها بس يكمّل قراءة الصفحة.
السبب إن السكربت القديم كان يقدر يكتب في الصفحة وهي بتتبني عن طريق document.write، فالمتصفح بيلعب على المضمون ويوقف كل حاجة لحد ما السكربت يخلّص. النتيجة: المستخدم مبيشوفش أي محتوى قبل ما السكربت ينزل ويشتغل. المصطلح الرسمي للمورد اللي بيعمل كده اسمه render-blocking resource، أي مورد يحجب الرسم.
الحل: خاصيتين اسمهم defer و async
الحل إنك تقول للمتصفح: "نزّل السكربت وانت ماشي، بس متوقفش الصفحة عشانه". وده بيتعمل بإضافة كلمة واحدة على الوسم.
<!-- الطريقة الشائعة الغلط: بيوقف رسم الصفحة -->
<head>
<script src="/js/app.js"></script>
</head>
<!-- الأفضل: defer — نزّل بالتوازي، وشغّل بعد ما الصفحة تتبني -->
<head>
<script defer src="/js/app.js"></script>
</head>