بهینه سازی بارگیری منابع

در ماژول قبلی، برخی از تئوری‌های پشت مسیر رندر بحرانی مورد بررسی قرار گرفت و اینکه چگونه منابع رندر-انسداد و مسدودکننده تجزیه می‌توانند رندر اولیه صفحه را به تاخیر بیندازند. اکنون که برخی از نظریه‌های پشت این موضوع را درک کرده‌اید، آماده یادگیری تکنیک‌هایی برای بهینه‌سازی مسیر رندر بحرانی هستید.

با بارگیری صفحه، منابع زیادی در HTML آن ارجاع می‌شوند که ظاهر و طرح‌بندی صفحه را از طریق CSS و همچنین تعامل آن را از طریق جاوا اسکریپت ارائه می‌کنند. در این ماژول، تعدادی از مفاهیم مهم مرتبط با این منابع و نحوه تاثیر آنها بر زمان بارگذاری صفحه پوشش داده شده است.

رندر مسدود کردن

همانطور که در ماژول قبلی مورد بحث قرار گرفت، CSS یک منبع مسدودکننده رندر است، زیرا مرورگر را از رندر کردن هر محتوایی تا زمانی که مدل شیء CSS (CSSOM) ساخته شود، مسدود می‌کند. مرورگر رندر را مسدود می کند تا از فلش محتوای بدون سبک (FOUC) جلوگیری کند که از دیدگاه تجربه کاربر نامطلوب است.

در ویدیوی قبلی، یک FOUC مختصر وجود دارد که در آن می‌توانید صفحه را بدون هیچ استایلی ببینید. متعاقباً، پس از اتمام بارگذاری CSS صفحه از شبکه، همه سبک‌ها اعمال می‌شوند و نسخه بدون استایل صفحه بلافاصله با نسخه استایل‌شده جایگزین می‌شود.

به طور کلی، FOUC چیزی است که معمولاً نمی‌بینید، اما درک مفهوم آن مهم است تا بدانید چرا مرورگر جلوی رندر صفحه را می‌گیرد تا زمانی که CSS دانلود و در صفحه اعمال شود. مسدود کردن رندر لزوماً نامطلوب نیست، اما می‌خواهید با بهینه‌سازی CSS خود مدت زمان آن را به حداقل برسانید.

مسدود کردن تجزیه کننده

یک منبع مسدودکننده تجزیه کننده، تجزیه کننده HTML را قطع می کند، مانند یک عنصر <script> بدون ویژگی های async یا defer . هنگامی که تجزیه کننده با عنصر <script> مواجه می شود، مرورگر باید قبل از ادامه تجزیه بقیه HTML اسکریپت را ارزیابی و اجرا کند. این بر اساس طراحی است، زیرا اسکریپت ها ممکن است در مدت زمانی که هنوز در حال ساخت است DOM را تغییر دهند یا به آن دسترسی پیدا کنند.

<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>

هنگام استفاده از فایل های جاوا اسکریپت خارجی (بدون async یا defer )، تجزیه کننده از زمانی که فایل کشف شد تا زمانی که دانلود، تجزیه و اجرا شود مسدود می شود. هنگام استفاده از جاوا اسکریپت درون خطی، تجزیه کننده به طور مشابه تا زمانی که اسکریپت درون خطی تجزیه و اجرا شود مسدود می شود.

اسکنر پیش بارگذاری

اسکنر پیش بارگذاری یک بهینه‌سازی مرورگر در قالب یک تجزیه‌کننده HTML ثانویه است که پاسخ HTML خام را اسکن می‌کند تا منابع را قبل از اینکه تجزیه‌کننده HTML اولیه در غیر این صورت آن‌ها را کشف کند، بیابد و به صورت فرضی واکشی کند. به عنوان مثال، اسکنر پیش بارگذاری به مرورگر اجازه می دهد تا دانلود منبع مشخص شده در عنصر <img> را شروع کند، حتی زمانی که تجزیه کننده HTML در حین واکشی و پردازش منابعی مانند CSS و جاوا اسکریپت مسدود شده باشد.

برای استفاده از اسکنر پیش بارگذاری، منابع مهم باید در نشانه گذاری HTML ارسال شده توسط سرور گنجانده شود. الگوهای بارگذاری منابع زیر توسط اسکنر پیش بارگذاری قابل کشف نیستند:

  • تصاویر بارگذاری شده توسط CSS با استفاده از ویژگی background-image . این مراجع تصویر در CSS هستند و توسط اسکنر پیش بارگذاری قابل شناسایی نیستند.
  • اسکریپت های بارگذاری شده پویا به شکل نشانه گذاری عنصر <script> که با استفاده از جاوا اسکریپت یا ماژول هایی که با استفاده از import() پویا بارگذاری شده اند به DOM تزریق می شوند.
  • HTML با استفاده از جاوا اسکریپت بر روی کلاینت ارائه شده است. چنین نشانه‌گذاری در رشته‌های منابع جاوا اسکریپت وجود دارد و توسط اسکنر پیش‌بارگیری قابل کشف نیست.
  • CSS @import اعلامیه ها.

این الگوهای بارگذاری منابع همگی منابعی هستند که دیر کشف شده اند و بنابراین از اسکنر پیش بارگذاری سودی نمی برند. تا حد امکان از آنها دوری کنید. با این حال، اگر اجتناب از چنین الگوهایی ممکن نیست ، ممکن است بتوانید از یک راهنمایی preload برای جلوگیری از تأخیر در کشف منابع استفاده کنید.

CSS

CSS نمایش و طرح بندی یک صفحه را تعیین می کند. همانطور که قبلا توضیح داده شد، CSS یک منبع مسدود کننده رندر است، بنابراین بهینه سازی CSS شما می تواند تاثیر قابل توجهی بر زمان بارگذاری کلی صفحه داشته باشد.

کوچک سازی

کوچک کردن فایل‌های CSS، حجم فایل یک منبع CSS را کاهش می‌دهد و دانلود آن‌ها را سریع‌تر می‌کند. این کار عمدتاً با حذف محتوا از یک فایل CSS منبع مانند فاصله ها و سایر کاراکترهای نامرئی و خروجی نتیجه به یک فایل بهینه شده جدید انجام می شود:

/* Unminified CSS: */

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

در ابتدایی ترین شکل خود، کوچک سازی CSS یک بهینه سازی موثر است که می تواند FCP وب سایت شما و شاید حتی LCP را در برخی موارد بهبود بخشد. ابزارهایی مانند باندلرها می توانند به طور خودکار این بهینه سازی را برای شما در ساخت های تولیدی انجام دهند.

CSS استفاده نشده را حذف کنید

قبل از رندر کردن هر محتوا، مرورگر باید تمام شیوه نامه ها را دانلود و تجزیه کند. زمان لازم برای تکمیل تجزیه همچنین شامل سبک هایی است که در صفحه فعلی استفاده نمی شوند. اگر از یک بسته‌بندی استفاده می‌کنید که تمام منابع CSS را در یک فایل واحد ترکیب می‌کند، کاربران شما احتمالاً بیشتر از مقدار مورد نیاز برای ارائه صفحه فعلی CSS دانلود می‌کنند.

برای کشف CSS استفاده نشده برای صفحه فعلی، از ابزار Coverage در Chrome DevTools استفاده کنید.

تصویری از ابزار پوشش در Chrome DevTools. یک فایل CSS در قسمت پایین آن انتخاب شده است که مقدار قابل توجهی از CSS را نشان می دهد که توسط طرح بندی صفحه فعلی استفاده نشده است.
ابزار پوشش در Chrome DevTools برای تشخیص CSS (و جاوا اسکریپت) استفاده نشده توسط صفحه فعلی مفید است. می‌توان از آن برای تقسیم فایل‌های CSS به منابع متعدد برای بارگیری توسط صفحات مختلف استفاده کرد، برخلاف ارسال یک بسته CSS بسیار بزرگ‌تر که می‌تواند رندر صفحه را به تاخیر بیندازد.

حذف CSS استفاده نشده تاثیری دوگانه دارد: علاوه بر کاهش زمان دانلود، ساخت درخت رندر را بهینه می‌کنید، زیرا مرورگر باید قوانین CSS کمتری را پردازش کند.

از اعلان‌های CSS @import اجتناب کنید

اگرچه ممکن است راحت به نظر برسد، باید از اعلان @import در CSS اجتناب کنید:

/* Don't do this: */
@import url('style.css');

مشابه نحوه عملکرد عنصر <link> در HTML، اعلان @import در CSS به شما امکان می دهد یک منبع CSS خارجی را از داخل یک style sheet وارد کنید. تفاوت عمده بین این دو رویکرد این است که عنصر <link> HTML بخشی از پاسخ HTML است و بنابراین خیلی زودتر از یک فایل CSS دانلود شده توسط یک اعلان @import کشف می شود.

دلیل این امر این است که برای اینکه یک اعلان @import کشف شود، ابتدا باید فایل CSS که حاوی آن است دانلود شود. این منجر به چیزی می شود که به عنوان زنجیره درخواست شناخته می شود که - در مورد CSS - مدت زمان لازم برای ارائه اولیه صفحه را به تاخیر می اندازد. اشکال دیگر این است که شیوه نامه های بارگذاری شده با استفاده از یک اعلان @import نمی توانند توسط اسکنر پیش بارگذاری کشف شوند و بنابراین تبدیل به منابع مسدودکننده رندر دیر کشف شده می شوند.

<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">

در بیشتر موارد، می‌توانید با استفاده از عنصر <link rel="stylesheet"> @import جایگزین کنید. عناصر <link> به شیوه نامه ها اجازه می دهند که به طور همزمان بارگیری شوند و زمان بارگیری کلی را کاهش می دهند، برخلاف اعلامیه های @import ، که شیوه نامه ها را به طور متوالی دانلود می کنند.

CSS بحرانی درون خطی

زمان لازم برای دانلود فایل های CSS می تواند FCP صفحه را افزایش دهد. درون‌سازی سبک‌های حیاتی در سند <head> درخواست شبکه برای یک منبع CSS را حذف می‌کند، و - در صورت انجام صحیح - می‌تواند زمان بارگذاری اولیه را در زمانی که حافظه پنهان مرورگر کاربر آماده نشده است، بهبود بخشد. CSS باقی مانده را می توان به صورت ناهمزمان بارگذاری کرد، یا در انتهای عنصر <body> اضافه کرد.

<head>
  <title>Page Title</title>
  <!-- ... -->
  <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
  <!-- Other page markup... -->
  <link rel="stylesheet" href="non-critical.css">
</body>

از جنبه منفی، داخل کردن مقدار زیادی از CSS، بایت های بیشتری را به پاسخ اولیه HTML اضافه می کند. از آنجا که منابع HTML اغلب نمی‌توانند برای مدت طولانی یا اصلاً ذخیره شوند، این بدان معناست که CSS درون‌بندی شده برای صفحات بعدی که ممکن است از همان CSS در شیوه نامه‌های خارجی استفاده کنند، ذخیره نمی‌شود. عملکرد صفحه خود را تست و اندازه گیری کنید تا مطمئن شوید که مبادلات ارزش تلاش را دارند.

دموهای CSS

جاوا اسکریپت

جاوا اسکریپت بیشتر تعامل در وب را هدایت می کند، اما هزینه ای دارد. ارسال بیش از حد جاوا اسکریپت می تواند باعث کند صفحه وب شما در حین بارگذاری صفحه پاسخ دهد، و حتی ممکن است باعث بروز مشکلاتی در پاسخگویی شود که تعاملات را کاهش می دهد - که هر دو می توانند برای کاربران خسته کننده باشند.

جاوا اسکریپت مسدود کننده رندر

هنگام بارگیری عناصر <script> بدون ویژگی‌های defer یا async ، مرورگر تجزیه و رندر را تا زمانی که اسکریپت دانلود، تجزیه و اجرا شود مسدود می‌کند. به طور مشابه، اسکریپت های درون خطی تجزیه کننده را مسدود می کنند تا زمانی که اسکریپت تجزیه و اجرا شود.

async در مقابل defer

async و defer به اسکریپت های خارجی اجازه بارگیری بدون مسدود کردن تجزیه کننده HTML را می دهند در حالی که اسکریپت ها (از جمله اسکریپت های درون خطی) با type="module" به طور خودکار به تعویق می افتند. با این حال، async و defer تفاوت‌هایی دارند که درک آن‌ها مهم است.

تصویری از مکانیسم‌های مختلف بارگذاری اسکریپت، که همگی نقش‌های تجزیه‌کننده، واکشی و اجرا را بر اساس ویژگی‌های مختلف مورد استفاده مانند async، defer، type='module' و ترکیبی از هر سه جزئیات نشان می‌دهند.
منبع از https://html.spec.whatwg.org/multipage/scripting.html

اسکریپت های بارگذاری شده با async بلافاصله پس از دانلود تجزیه و اجرا می شوند، در حالی که اسکریپت های بارگذاری شده با defer زمانی که تجزیه سند HTML به پایان رسید اجرا می شوند - این همزمان با رویداد DOMContentLoaded مرورگر رخ می دهد. علاوه بر این، اسکریپت‌های async ممکن است خارج از نظم اجرا شوند، در حالی که اسکریپت‌های defer به ترتیبی که در نشانه‌گذاری ظاهر می‌شوند اجرا می‌شوند.

رندر سمت مشتری

به طور کلی، باید از استفاده از جاوا اسکریپت برای ارائه هر محتوای مهم یا عنصر LCP صفحه اجتناب کنید. این به عنوان رندر سمت مشتری شناخته می شود و تکنیکی است که به طور گسترده در برنامه های کاربردی صفحه تک (SPA) استفاده می شود.

نشانه گذاری ارائه شده توسط جاوا اسکریپت اسکنر پیش بارگذاری را کنار می گذارد، زیرا منابع موجود در نشانه گذاری ارائه شده توسط مشتری توسط آن قابل کشف نیستند . این می تواند دانلود منابع مهم مانند یک تصویر LCP را به تاخیر بیندازد. مرورگر فقط پس از اجرای اسکریپت شروع به دانلود تصویر LCP می کند و عنصر را به DOM اضافه می کند. به نوبه خود، اسکریپت تنها پس از کشف، دانلود و تجزیه می تواند اجرا شود. این به عنوان یک زنجیره درخواست بحرانی شناخته می شود و باید از آن اجتناب شود.

علاوه بر این، رندر نشانه گذاری با استفاده از جاوا اسکریپت نسبت به نشانه گذاری دانلود شده از سرور در پاسخ به درخواست ناوبری، به احتمال زیاد کارهای طولانی را ایجاد می کند. استفاده گسترده از رندر سمت سرویس گیرنده HTML می تواند بر تأخیر تعامل تأثیر منفی بگذارد . این امر به ویژه در مواردی که DOM صفحه بسیار بزرگ است صادق است، که وقتی جاوا اسکریپت DOM را تغییر می‌دهد، کار رندر قابل توجهی را آغاز می‌کند.

کوچک سازی

مشابه CSS، کوچک کردن جاوا اسکریپت اندازه فایل منبع اسکریپت را کاهش می دهد. این می‌تواند منجر به دانلود سریع‌تر شود و به مرورگر اجازه می‌دهد تا فرآیند تجزیه و کامپایل جاوا اسکریپت را سریع‌تر انجام دهد.

علاوه بر این، کوچک سازی جاوا اسکریپت یک قدم فراتر از کوچک کردن سایر دارایی ها مانند CSS است. هنگامی که جاوا اسکریپت کوچک می شود، نه تنها از مواردی مانند فاصله، برگه ها و نظرات حذف می شود، بلکه نمادها در جاوا اسکریپت منبع کوتاه می شوند. این فرآیند گاهی اوقات به عنوان زشت نامیده می شود. برای مشاهده تفاوت، کد منبع جاوا اسکریپت زیر را بگیرید:

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}

هنگامی که کد منبع جاوا اسکریپت قبلی uglified شود، نتیجه ممکن است چیزی شبیه به قطعه کد زیر باشد:

// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

در قطعه قبلی، می بینید که scriptElement متغیر قابل خواندن توسط انسان در منبع به t کوتاه شده است. هنگامی که در مجموعه بزرگی از اسکریپت ها اعمال می شود، صرفه جویی می تواند بسیار قابل توجه باشد، بدون اینکه بر ویژگی هایی که جاوا اسکریپت تولید یک وب سایت ارائه می دهد تأثیر بگذارد.

اگر از یک باندلر برای پردازش کد منبع وب سایت خود استفاده می کنید، uglification اغلب به صورت خودکار برای ساخت های تولیدی انجام می شود. Uglifiers - مانند Terser ، برای مثال - همچنین بسیار قابل تنظیم هستند، که به شما امکان می دهد تهاجمی الگوریتم uglification را برای دستیابی به حداکثر صرفه جویی تغییر دهید. با این حال، پیش‌فرض‌های هر ابزار زشت‌سازی معمولاً برای ایجاد تعادل مناسب بین اندازه خروجی و حفظ قابلیت‌ها کافی است.

دموهای جاوا اسکریپت

دانش خود را آزمایش کنید

بهترین راه برای بارگذاری چندین فایل CSS در مرورگر چیست؟

اعلامیه CSS @import .
دوباره امتحان کنید.
عناصر <link> متعدد.
درسته!

اسکنر پیش بارگذاری مرورگر چه می کند؟

این یک تجزیه کننده HTML ثانویه است که نشانه گذاری خام را برای کشف منابع قبل از تجزیه کننده DOM بررسی می کند تا زودتر آنها را کشف کند.
درسته!
عناصر <link rel="preload"> را در یک منبع HTML شناسایی می کند.
دوباره امتحان کنید.

چرا مرورگر هنگام دانلود منابع جاوا اسکریپت به طور پیش فرض تجزیه HTML را به طور موقت مسدود می کند؟

برای جلوگیری از فلش محتوای بدون سبک (FOUC).
دوباره امتحان کنید.
زیرا ارزیابی جاوا اسکریپت یک کار بسیار فشرده CPU است و توقف تجزیه HTML پهنای باند بیشتری به CPU می دهد تا بارگذاری اسکریپت ها را به پایان برساند.
دوباره امتحان کنید.
زیرا اسکریپت ها می توانند DOM را تغییر دهند یا به شکل دیگری به آن دسترسی داشته باشند.
درسته!

بعدی: کمک به مرورگر با نکات منابع

اکنون که کنترلی در مورد اینکه چگونه منابع بارگذاری شده در عنصر <head> می‌تواند بر بارگذاری صفحه اولیه و معیارهای مختلف تأثیر بگذارد، وقت آن رسیده است که به کار خود ادامه دهید. در ماژول بعدی، نکات منابع مورد بررسی قرار می‌گیرند، و اینکه چگونه می‌توانند نکات ارزشمندی را به مرورگر بدهند تا زودتر از مرورگر بدون آنها، منابع را بارگیری کند و اتصالات را به سرورهای متقاطع باز کند.