دریابید که اسکنر پیش بارگذاری مرورگر چیست، چگونه به عملکرد کمک می کند و چگونه می توانید از راه خود دور بمانید.
یکی از جنبه های نادیده گرفته شده بهینه سازی سرعت صفحه شامل دانستن اندکی در مورد داخلی مرورگر است. مرورگرها بهینهسازیهای خاصی را برای بهبود عملکرد به روشهایی انجام میدهند که ما بهعنوان توسعهدهنده نمیتوانیم - اما تا زمانی که این بهینهسازیها ناخواسته خنثی نشده باشند.
یکی از بهینهسازیهای داخلی مرورگر برای درک، اسکنر پیش بارگذاری مرورگر است. این پست نحوه عملکرد اسکنر پیش بارگذاری و مهمتر از آن، چگونگی جلوگیری از قرار گرفتن در مسیر آن را پوشش خواهد داد.
اسکنر پیش بارگذاری چیست؟
هر مرورگر دارای یک تجزیه کننده اولیه HTML است که نشانه گذاری خام را نشانه گذاری می کند و آن را به یک مدل شی پردازش می کند. همه اینها با خوشحالی ادامه مییابد تا زمانی که تجزیهکننده وقتی یک منبع مسدودکننده را پیدا میکند، مانند یک شیوه نامه بارگذاری شده با عنصر <link>
، یا اسکریپت بارگیری شده با عنصر <script>
بدون ویژگی async
یا defer
، متوقف میشود.
در مورد فایلهای CSS، رندر برای جلوگیری از فلش محتوای بدون استایل (FOUC) مسدود میشود، یعنی زمانی که یک نسخه بدون استایل یک صفحه قبل از اعمال سبکها به آن بهطور مختصر دیده میشود.
مرورگر همچنین هنگام برخورد با عناصر <script>
بدون ویژگی defer
یا async
تجزیه و رندر صفحه را مسدود می کند.
دلیل این امر این است که مرورگر نمی تواند با اطمینان بداند که آیا هر اسکریپت داده شده DOM را تغییر می دهد در حالی که تجزیه کننده اولیه HTML هنوز کار خود را انجام می دهد. به همین دلیل است که بارگذاری جاوا اسکریپت خود در انتهای سند به طوری که اثرات تجزیه و رندر مسدود شده حاشیه ای شود، یک روش معمول بوده است.
اینها دلایل خوبی برای این است که چرا مرورگر باید هم تجزیه و هم رندر را مسدود کند. با این حال، مسدود کردن هر یک از این مراحل مهم نامطلوب است، زیرا آنها می توانند نمایش را با تاخیر در کشف منابع مهم دیگر حفظ کنند. خوشبختانه، مرورگرها تمام تلاش خود را برای کاهش این مشکلات از طریق یک تجزیه کننده HTML ثانویه به نام اسکنر پیش بارگذاری انجام می دهند.
نقش یک اسکنر پیش بارگذاری گمانهزنی است ، به این معنی که نشانهگذاری خام را به منظور یافتن منابعی برای واکشی فرصتطلبانه قبل از تجزیهکننده اولیه HTML بررسی میکند.
چگونه بفهمیم اسکنر پیش بارگذاری چه زمانی کار می کند
اسکنر پیش بارگذاری به دلیل رندر و تجزیه مسدود شده وجود دارد. اگر این دو مشکل عملکرد هرگز وجود نداشت، اسکنر پیش بارگذاری چندان مفید نخواهد بود. کلید فهمیدن اینکه آیا یک صفحه وب از اسکنر پیش بارگذاری سود می برد یا خیر به این پدیده های مسدود کننده بستگی دارد. برای انجام این کار، میتوانید یک تاخیر مصنوعی برای درخواستها معرفی کنید تا بفهمید اسکنر پیشبارگذاری کجا کار میکند.
این صفحه متن و تصاویر اصلی را با یک شیوه نامه به عنوان مثال در نظر بگیرید. از آنجایی که فایلهای CSS هم رندر و هم تجزیه را مسدود میکنند، شما یک تاخیر مصنوعی دو ثانیهای را برای شیوه نامه از طریق یک سرویس پروکسی معرفی میکنید. این تاخیر باعث می شود که در آبشار شبکه جایی که اسکنر پیش بارگذاری کار می کند، راحت تر دیده شود.
همانطور که در آبشار می بینید، اسکنر پیش بارگذاری عنصر <img>
را حتی زمانی که رندر و تجزیه سند مسدود شده است، کشف می کند. بدون این بهینهسازی، مرورگر نمیتواند موارد را بهطور فرصتطلبانه در طول دوره مسدود کردن واکشی کند و درخواستهای منابع بیشتر متوالی خواهد بود تا همزمان.
با وجود این نمونه اسباببازی، بیایید نگاهی به برخی از الگوهای دنیای واقعی بیندازیم که در آنها میتوان اسکنر پیشبارگذاری را شکست داد – و برای رفع آنها چه کاری میتوان انجام داد.
اسکریپت های async
تزریق شد
فرض کنید HTML در <head>
خود دارید که شامل جاوا اسکریپت داخلی مانند این است:
<script>
const scriptEl = document.createElement('script');
scriptEl.src = '/yall.min.js';
document.head.appendChild(scriptEl);
</script>
اسکریپت های تزریق شده به طور پیش فرض async
هستند، بنابراین وقتی این اسکریپت تزریق می شود، طوری رفتار می کند که گویی ویژگی async
روی آن اعمال شده است. یعنی در اسرع وقت اجرا می شود و رندر را مسدود نمی کند. به نظر بهینه می رسد، درست است؟ با این حال، اگر فرض کنید که این <script>
درون خطی بعد از یک عنصر <link>
که یک فایل CSS خارجی را بارگیری میکند میآید، یک نتیجه کمتر از حد مطلوب دریافت خواهید کرد:
بیایید آنچه را که در اینجا رخ داده است، تجزیه کنیم:
- در 0 ثانیه، سند اصلی درخواست می شود.
- در 1.4 ثانیه، اولین بایت درخواست ناوبری می رسد.
- در 2.0 ثانیه، CSS و تصویر درخواست می شود.
- از آنجایی که تجزیه کننده هنگام بارگیری شیوه نامه مسدود شده است و جاوا اسکریپت درون خطی که اسکریپت
async
را تزریق می کند در 2.6 ثانیه بعد از آن شیوه نامه می آید، عملکردی که اسکریپت ارائه می دهد به زودی در دسترس نیست.
این کمتر از حد بهینه است زیرا درخواست اسکریپت تنها پس از پایان بارگیری صفحه سبک انجام می شود. این امر اجرای هر چه سریعتر اسکریپت را به تاخیر می اندازد. در مقابل، چون عنصر <img>
در نشانه گذاری ارائه شده توسط سرور قابل کشف است، توسط اسکنر پیش بارگذاری کشف می شود.
بنابراین، اگر از یک تگ <script>
معمولی با ویژگی async
به جای تزریق اسکریپت به DOM استفاده کنید، چه اتفاقی میافتد؟
<script src="/yall.min.js" async></script>
این هم نتیجه:
ممکن است وسوسه ای وجود داشته باشد که پیشنهاد کنیم این مشکلات را می توان با استفاده از rel=preload
اصلاح کرد. این مطمئناً کار می کند، اما ممکن است عوارض جانبی داشته باشد. به هر حال، چرا از rel=preload
برای رفع مشکلی استفاده می کنیم که با تزریق نکردن عنصر <script>
به DOM می توان از آن جلوگیری کرد؟
بارگذاری از قبل مشکل را در اینجا "رفع" می کند، اما یک مشکل جدید را معرفی می کند: اسکریپت async
در دو دمو اول - علیرغم بارگیری در <head>
- در اولویت "Low" بارگذاری می شود، در حالی که شیوه نامه در "Highest" بارگذاری می شود. اولویت در آخرین نسخه نمایشی که اسکریپت async
از قبل بارگذاری شده است، شیوه نامه همچنان در اولویت "بالاترین" بارگیری می شود، اما اولویت اسکریپت به "بالا" ارتقا یافته است.
هنگامی که اولویت یک منبع افزایش می یابد، مرورگر پهنای باند بیشتری را به آن اختصاص می دهد. این بدان معنی است که - حتی اگر شیوه نامه بالاترین اولویت را دارد - اولویت افزایش یافته اسکریپت ممکن است باعث ایجاد اختلاف در پهنای باند شود. این می تواند عاملی در اتصالات کند یا در مواردی باشد که منابع بسیار زیاد هستند.
پاسخ در اینجا ساده است: اگر در هنگام راهاندازی به اسکریپت نیاز است، اسکنر پیشبارگذاری را با تزریق آن به DOM شکست ندهید. در صورت نیاز با قرار دادن عنصر <script>
و همچنین با ویژگی هایی مانند defer
و async
آزمایش کنید.
بارگذاری تنبل با جاوا اسکریپت
بارگذاری تنبل یک روش عالی برای حفظ داده است، روشی که اغلب بر روی تصاویر اعمال می شود. با این حال، گاهی اوقات بارگذاری تنبل به اشتباه روی تصاویری که به اصطلاح «در بالای صفحه» هستند اعمال می شود.
این موضوع مشکلات بالقوه ای را در مورد قابلیت کشف منبع در مورد اسکنر پیش بارگذاری معرفی می کند و می تواند به طور غیرضروری مدت زمان لازم برای کشف یک مرجع به یک تصویر، دانلود آن، رمزگشایی و ارائه آن را به تاخیر بیاندازد. بیایید این نشانه گذاری تصویر را به عنوان مثال در نظر بگیریم:
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
استفاده از پیشوند data-
یک الگوی رایج در لودرهای تنبل با جاوا اسکریپت است. هنگامی که تصویر به نمای درگاه اسکرول می شود، لودر تنبل پیشوند data-
حذف می کند، به این معنی که در مثال قبل، data-src
به src
تبدیل می شود. این به روز رسانی از مرورگر می خواهد که منبع را واکشی کند.
این الگو تا زمانی که روی تصاویری که در هنگام راهاندازی در نمای نمایش هستند اعمال نشود مشکل ساز نیست. از آنجایی که اسکنر پیش بارگذاری ویژگی data-src
را به همان روشی که ویژگی src
(یا srcset
) می خواند، نمی خواند، مرجع تصویر زودتر کشف نمی شود. بدتر از آن، بارگیری تصویر تا زمانی که بارگذار تنبل جاوا اسکریپت بارگیری، کامپایل و اجرا شود به تأخیر می افتد.
بسته به اندازه تصویر - که ممکن است به اندازه درگاه دید بستگی داشته باشد - ممکن است یک عنصر نامزد برای بزرگترین رنگ محتوایی (LCP) باشد. هنگامی که اسکنر پیش بارگذاری نمی تواند منبع تصویر را پیش از موعد واکشی کند - احتمالاً در نقطه ای که صفحه سبک (های) صفحه نمایش را مسدود می کند - LCP آسیب می بیند.
راه حل این است که نشانه گذاری تصویر را تغییر دهید:
<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
این الگوی بهینه برای تصاویری است که در هنگام راهاندازی در نما هستند، زیرا اسکنر پیشبارگذاری منبع تصویر را سریعتر کشف و واکشی میکند.
نتیجه در این مثال ساده شده بهبود 100 میلی ثانیه ای در LCP در یک اتصال آهسته است. این ممکن است پیشرفت بزرگی به نظر نرسد، اما زمانی است که فکر میکنید راهحل یک اصلاح سریع نشانهگذاری است و بیشتر صفحات وب پیچیدهتر از این مجموعه نمونهها هستند. این بدان معناست که نامزدهای LCP ممکن است مجبور باشند برای پهنای باند با بسیاری از منابع دیگر مبارزه کنند، بنابراین بهینه سازی هایی مانند این اهمیت فزاینده ای پیدا می کنند.
تصاویر پس زمینه CSS
به یاد داشته باشید که اسکنر پیش بارگذاری مرورگر نشانه گذاری را اسکن می کند . انواع دیگر منابع مانند CSS را که ممکن است شامل واکشی برای تصاویر ارجاع شده توسط ویژگی background-image
باشد ، اسکن نمی کند.
مانند HTML، مرورگرها CSS را به مدل شیء خود پردازش می کنند که به نام CSSOM شناخته می شود. اگر منابع خارجی در حین ساخت CSSOM کشف شوند، آن منابع در زمان کشف درخواست می شوند و نه توسط اسکنر پیش بارگذاری.
فرض کنید کاندید LCP صفحه شما یک عنصر با ویژگی background-image
CSS است. موارد زیر هنگام بارگیری منابع اتفاق می افتد:
در این مورد، اسکنر پیش بارگذاری آنقدر شکست نمی خورد که درگیر نمی شود. با این حال، اگر یک نامزد LCP در صفحه از یک ویژگی CSS background-image
باشد، میخواهید آن تصویر را از قبل بارگذاری کنید:
<!-- Make sure this is in the <head> below any
stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">
این راهنمایی rel=preload
کوچک است، اما به مرورگر کمک می کند تا تصویر را زودتر از آنچه در غیر این صورت انجام می داد، کشف کند:
با اشاره rel=preload
، نامزد LCP زودتر کشف می شود و زمان LCP را کاهش می دهد. در حالی که این راهنمایی به رفع این مشکل کمک می کند، گزینه بهتر ممکن است ارزیابی این باشد که آیا نامزد LCP تصویر شما باید از CSS بارگیری شود یا خیر. با یک تگ <img>
، کنترل بیشتری بر بارگذاری تصویری که برای نمای نمایش مناسب است خواهید داشت و در عین حال به اسکنر پیش بارگذاری اجازه میدهید آن را کشف کند.
گنجاندن منابع بسیار زیاد
Inlining عملی است که یک منبع را در داخل HTML قرار می دهد. میتوانید شیوه نامهها را در عناصر <style>
، اسکریپتها در عناصر <script>
و تقریباً هر منبع دیگری را با استفاده از کدگذاری base64 درون خطی کنید.
منابع داخلی می تواند سریعتر از دانلود آنها باشد زیرا درخواست جداگانه ای برای منبع صادر نمی شود. درست در سند است و فوراً بارگیری می شود. با این حال، اشکالات قابل توجهی وجود دارد:
- اگر HTML خود را در حافظه پنهان ذخیره نمی کنید - و اگر پاسخ HTML پویا باشد نمی توانید - منابع درون خطی هرگز کش نمی شوند. این بر عملکرد تأثیر می گذارد زیرا منابع درون خطی قابل استفاده مجدد نیستند.
- حتی اگر بتوانید HTML را حافظه پنهان کنید، منابع درون خطی بین اسناد به اشتراک گذاشته نمی شود. این کار راندمان کش را در مقایسه با فایلهای خارجی که میتوان آنها را در حافظه پنهان ذخیره کرد و در کل یک منبع دوباره استفاده کرد، کاهش میدهد.
- اگر بیش از حد خط خطی کنید، اسکنر پیش بارگذاری را از کشف منابع بعدی در سند به تأخیر می اندازید، زیرا دانلود آن محتوای اضافی و خطی بیشتر طول می کشد.
این صفحه را به عنوان مثال در نظر بگیرید. در شرایط خاص، کاندید LCP تصویر بالای صفحه است و CSS در یک فایل جداگانه است که توسط عنصر <link>
بارگذاری شده است. این صفحه همچنین از چهار فونت وب استفاده می کند که به عنوان فایل های جداگانه از منبع CSS درخواست می شوند.
حال اگر CSS و تمام فونت ها به عنوان منابع base64 خط بندی شوند چه اتفاقی می افتد؟
تأثیر inlining پیامدهای منفی برای LCP در این مثال و عملکرد به طور کلی به همراه دارد. نسخه ای از صفحه که هیچ چیزی را درون خطی نمی کند، تصویر LCP را در حدود 3.5 ثانیه رنگ می کند. صفحهای که همه چیز را در آن قرار میدهد، تصویر LCP را تا بیش از ۷ ثانیه ترسیم نمیکند.
در اینجا چیزهای بیشتری از اسکنر پیش بارگذاری وجود دارد. فونت های درون خطی استراتژی خوبی نیست زیرا base64 قالبی ناکارآمد برای منابع باینری است. عامل دیگر این است که منابع فونت خارجی دانلود نمی شوند مگر اینکه توسط CSSOM ضروری تشخیص داده شوند. وقتی آن فونتها بهعنوان base64 خطبندی میشوند، چه برای صفحه فعلی مورد نیاز باشند چه نباشند، دانلود میشوند.
آیا یک پیش بارگذاری می تواند همه چیز را در اینجا بهبود بخشد؟ مطمئنا میتوانید تصویر LCP را از قبل بارگذاری کنید و زمان LCP را کاهش دهید، اما پرکردن HTML غیرقابل ذخیرهسازی بالقوهتان با منابع درونخط شده، پیامدهای عملکرد منفی دیگری دارد. First Contentful Paint (FCP) نیز تحت تأثیر این الگو قرار می گیرد. در نسخهای از صفحه که در آن هیچ چیز خطی نیست، FCP تقریباً 2.7 ثانیه است. در نسخه ای که همه چیز به صورت خطی است، FCP تقریباً 5.8 ثانیه است.
در داخل کردن مطالب در HTML، به خصوص منابع کدگذاری شده با base64 بسیار مراقب باشید. به طور کلی توصیه نمی شود، به جز برای منابع بسیار کم. تا جایی که ممکن است کمتر خط خطی کنید، زیرا خط کشی بیش از حد، بازی با آتش است.
رندر کردن نشانه گذاری با جاوا اسکریپت سمت سرویس گیرنده
شکی در آن نیست: جاوا اسکریپت قطعا بر سرعت صفحه تأثیر می گذارد . نه تنها توسعه دهندگان برای ارائه تعامل به آن وابسته هستند، بلکه تمایلی نیز وجود دارد که برای ارائه محتوا به آن اعتماد کنند. این امر از جهاتی منجر به تجربه بهتر توسعه دهنده می شود. اما مزایای توسعه دهندگان همیشه به مزایایی برای کاربران تبدیل نمی شود.
یکی از الگوهایی که میتواند اسکنر پیشبارگذاری را شکست دهد، نشانگذاری با جاوا اسکریپت سمت کلاینت است:
هنگامی که بارهای نشانه گذاری در مرورگر قرار می گیرند و به طور کامل توسط جاوا اسکریپت ارائه می شوند، هر منبعی در آن نشانه گذاری برای اسکنر پیش بارگذاری نامرئی است. این امر کشف منابع مهم را به تأخیر می اندازد که مطمئناً بر LCP تأثیر می گذارد. در مورد این مثالها، درخواست تصویر LCP در مقایسه با تجربه مشابه ارائهشده توسط سرور که برای نمایش نیازی به جاوا اسکریپت ندارد، بهطور قابلتوجهی به تأخیر میافتد.
این موضوع کمی از تمرکز این مقاله دور میشود، اما اثرات رندر نشانهگذاری بر روی مشتری بسیار فراتر از شکست اسکنر پیشبارگذاری است. برای مثال، معرفی جاوا اسکریپت برای تقویت تجربهای که نیازی به آن ندارد، زمان پردازش غیرضروری را معرفی میکند که میتواند بر تعامل با رنگ بعدی (INP) تأثیر بگذارد. ارائه مقادیر بسیار زیاد نشانه گذاری روی کلاینت در مقایسه با همان مقدار نشانه گذاری ارسال شده توسط سرور، به احتمال زیاد کارهای طولانی را ایجاد می کند. دلیل این امر - جدای از پردازش اضافی که جاوا اسکریپت شامل می شود - این است که مرورگرها نشانه گذاری را از سرور پخش می کنند و رندر را به گونه ای تقسیم می کنند که تمایل دارد کارهای طولانی را محدود کند. از سوی دیگر، نشانهگذاری ارائهشده توسط مشتری، به عنوان یک کار منفرد و یکپارچه مدیریت میشود که ممکن است بر INP صفحه تأثیر بگذارد.
راه حل این سناریو به پاسخ این سوال بستگی دارد: آیا دلیلی وجود دارد که نشانگذاری صفحه شما توسط سرور ارائه نمیشود و برخلاف اینکه روی کلاینت ارائه میشود؟ اگر پاسخ به این "نه" است، رندر سمت سرور (SSR) یا نشانهگذاری استاتیکی باید در صورت امکان در نظر گرفته شود، زیرا به اسکنر پیشبارگذاری کمک میکند تا منابع مهم را زودتر کشف کند و بهطور فرصتطلبانه واکشی کند.
اگر صفحه شما به جاوا اسکریپت نیاز دارد تا عملکردها را به برخی از بخشهای نشانهگذاری صفحهتان متصل کند، همچنان میتوانید این کار را با SSR انجام دهید، یا با جاوا اسکریپت وانیلی یا هیدراتاسیون برای به دست آوردن بهترین هر دو دنیا.
به اسکنر پیش بارگذاری کمک کنید تا به شما کمک کند
اسکنر پیش بارگذاری یک بهینهسازی مرورگر بسیار مؤثر است که به بارگذاری سریعتر صفحات در هنگام راهاندازی کمک میکند. با اجتناب از الگوهایی که توانایی آن را برای کشف منابع مهم پیش از موعد از بین میبرند، نه تنها توسعه را برای خود سادهتر میکنید، بلکه تجربیات کاربری بهتری ایجاد میکنید که نتایج بهتری را در بسیاری از معیارها، از جمله برخی موارد حیاتی وب ، ارائه میدهد.
برای جمع بندی، در اینجا موارد زیر وجود دارد که می خواهید از این پست حذف کنید:
- اسکنر پیش بارگذاری مرورگر یک تجزیهکننده HTML ثانویه است که در صورت مسدود شدن برای کشف فرصتطلبانه منابعی که میتواند زودتر دریافت کند، پیش از اسکنر اولیه اسکن میکند.
- منابعی که در نشانه گذاری ارائه شده توسط سرور در درخواست ناوبری اولیه وجود ندارند توسط اسکنر پیش بارگذاری قابل کشف نیستند. راه هایی که می توان اسکنر پیش بارگذاری را شکست داد ممکن است شامل موارد زیر باشد (اما محدود به موارد زیر نیست):
- تزریق منابع به DOM با جاوا اسکریپت، اعم از اسکریپت، تصاویر، شیوه نامه، یا هر چیز دیگری که در بارگذاری اولیه نشانه گذاری از سرور بهتر باشد.
- بارگذاری تنبل تصاویر یا آیفریم های بالا با استفاده از راه حل جاوا اسکریپت.
- ارائه نشانه گذاری روی کلاینت که ممکن است حاوی ارجاع به منابع فرعی سند با استفاده از جاوا اسکریپت باشد.
- اسکنر پیش بارگذاری فقط HTML را اسکن می کند. محتویات منابع دیگر - به ویژه CSS - که ممکن است شامل ارجاع به داراییهای مهم، از جمله نامزدهای LCP باشد را بررسی نمیکند.
اگر به هر دلیلی نمیتوانید از الگویی که بر توانایی اسکنر پیشبارگذاری برای سرعت بخشیدن به عملکرد بارگذاری تأثیر منفی میگذارد اجتناب کنید، اشاره منبع rel=preload
را در نظر بگیرید. اگر از rel=preload
استفاده می کنید ، در ابزارهای آزمایشگاهی تست کنید تا مطمئن شوید که اثر مورد نظر را به شما می دهد. در نهایت، منابع زیادی را از قبل بارگذاری نکنید، زیرا وقتی همه چیز را اولویت بندی کنید، هیچ چیز نخواهد بود.
منابع
- «اسکریپتهای ناهمگام» تزریقشده با اسکریپت مضر در نظر گرفته میشوند
- چگونه پیش بارگذاری مرورگر باعث می شود صفحات سریعتر بارگذاری شوند
- دارایی های حیاتی را برای بهبود سرعت بارگذاری از قبل بارگیری کنید
- برای بهبود سرعت درک شده صفحه، اتصالات شبکه را زودتر برقرار کنید
- بهینه سازی بزرگترین رنگ محتوایی
تصویر قهرمان از Unsplash اثر محمد رحمانی .