تست سرعت سایت: اسکریپت‌های مزاحم و خطای Render Blocking

کاربرانی که وسواس افزایش سرعت سایت خود را بنا به معیارهای تست سرعت گوگل و GTMetrix دارند، عموما با خطای مرسوم Render Blocking و تقاضای حذف آن را روبرو می‌شوند.خطای Render Blockingخود این خطا به زبان ساده دارد می‌گوید که در صفحه شما یک سری فایل -اعم از فونت، جاوااسکریپت یا CSS و غیره- وجود دارند که ابتدا باید دانلود و اجرا شوند تا بعد مابقی صفحه اجازه لود پیدا کند. بنابراین کاربر در این بازه زمانیِ دریافت و اجرای فایل‌ها امکان مشاهده یا استفاده از صفحه شما را ندارد و به ‌اصطلاح «بلاک» می‌شود.برای حل این مساله البته افزونه‌های بهینه‌سازی مثل W3 Total Cache، Autoptimize و غیره به کار می‌آیند. ولی این افزونه‌ها نیازمند تنظیمات بهینه هستند و تنظیمات بهینه هم نیازمند دانستن صورت مساله و منطق پشت آن.در غیر این صورت حکایت کاربرانی می‌شود که تصور می‌کنند صرف نصب و راه‌اندازی این افزونه‌ها قرار است معجزه کند. ولی وقتی نتیجه دلخواه را نمی‌گیرند و آب یخ رویشان ریخته می‌شود، یقه طراح افزونه را می‌گیرند.یک دسته از فایل‌هایی که باعث بروز این خطا می‌شوند، جاوااسکریپت‌ها هستند.اما داستان از چه قرارست؟برای درک مساله، یک صفحه HTML را با ساختار کلی زیر در نظر بگیرید:ساختار HTML فرضیمرورگر برای نمایش محتوای این صفحه به کاربر، باید کدها را از بالا به پایین بخواند تا در نهایت یک ساختار درختی یا داربست‌مانند (به ‌اصطلاح DOM) شکل بگیرد. اگر به تصویر بالا نگاه کنید می‌بینید که در طول فرایند ساخت این DOM، مرورگر به یک اسکریپت خارجی برخورد می‌کند که در قسمت پایین تگ Head قرار گرفته. پس الان ادامه فرایند ساخت DOM برای لحظاتی متوقف می‌شود تا مرورگر بتواند اول این اسکریپت را پیدا و اجرا کند (یعنی دو مرحله مجزا) و بعد به سراغ ادامه ساخت DOM برود (حالا در این مثال به جای اسکریپت خارجی، می‌تواند یک عکس، فیلم یا فایل استایل و خلاصه هر چیز دیگری قرار بگیرد، ولی در اینجا بحث ما فعلا روی همان اسکریپت متمرکز است).به این ترتیب تایملاین یا نقشه زمانی لود این صفحه چنین حالتی پیدا می‌کند:لود متقارن اسکریپت‌هااین حالت بدترین سناریوی ممکن است؛ چون تا زمانی که مروگر عملیات ساخت DOM را تمام نکرده باشد، کاربر نمی‌تواند محتوای صفحه وب را ببیند.انتقال اسکریپت به پایین صفحهبه همین خاطر توسعه‌دهندگان عموما اسکریپت‌های خارجی را به قسمت پایین صفحه (قبل از تگ </body>) منتقل می‌کنند تا به این ترتیب مرورگر فرصت داشته باشد که بخش بیشتری از محتوای صفحه را به کاربر نشان بدهد. در این حالت تایملاین بارگذاری صفحه چنین حالتی پیدا می‌کند:انتقال اسکریپت به پایین و نحوه لود صفحهتا اینجا با این کار گرچه لود صفحه سریع‌تر می‌شود و کاربر می‌تواند بخش بیشتری از صفحه را ببینید، ولی به محض رسیدن مرورگر به اسکریپت همچنان باید منتظر دریافت و اجرای آن و تکرار سناریوی قبلی بشود (به این حالت لود متقارن گفته می‌شود).ویژگی Asyncدر اینجاست که ویژگی Async (نامتقارن) به کمک شما می‌آید. در مثال قبل مرورگر با رسیدن به اسکریپت خارجی متوقف می‌شد تا بتواند آن را دریافت و اجرا کند.افزودن ویژگی async به اسکریپتاما در حالت جدید با اضافه کردن ویژگی Async، مرورگر می‌تواند همزمان با لودِ باقی محتوای صفحه و به شکل موازی، اسکریپت را دریافت کند؛ ولی همچنان برای اجرای اسکریپت باید لحظاتی متوقف شود (به همین خاطر این حالت لود نامتقارن خوانده می‌شود).نحوه لود صفحه هنگام استفاده از ویژگی async برای اسکریپت خارجیدر این مثال با استفاده از ویژگی Async می‌توانیم نسبت به سناریوی قبلی کمی در مدت زمان دریافت اسکریپت صرفه‌جویی کنیم. منتها با توجه به اینکه در ساختار HTML یک صفحه تگ‌های script زیادی می‌توانند وجود داشته باشند، بنابراین استفاده از ویژگی Async باعث می‌شود که روی هم رفته بشود زمان قابل‌توجهی را صرفه‌جویی کرد.ولی هنوز هم این سناریو ایده‌آل نیست. چون اولا تا اینجا فقط توانسته‌ایم مدت زمان دریافت اسکریپت را کمتر کنیم (در صورتی که مساله مهم‌تر بر سر مدت زمان اجرای آن است) و ثانیا ممکن است که کد جاوا اسکریپت شما برای اجرا نیازمند یکی از اشیای موجود در ساختار DOM باشد:مثلا اگر شما از روش Document.getElementById() برای فراخواندن یک دکمه و انجام یک عمل خاص استفاده کرده باشید، تا زمانی که این دکمه لود نشده باشد اسکریپت شما عمل نخواهد کرد. در این حالت اجرای اسکریپت، منوط به لود یکی از اشیای DOM است (این اتفاقا جواب سوالی است که قبلا در یک مطلب مطرح شده بود).ویژگی Deferپس در اینجا یک ویژگی دیگر به نام Defer وارد صحنه می‌شود که به همان سادگی Async قابل استفاده است.افزودن ویژگی defer به اسکریپت ویژگی Defer همانطور که از نامش پیداست، اجرای اسکریپت را موکول به زمانی می‌کند که ساختار DOM تشکیل شده و محتوای صفحه لود شده باشد.نحوه لود صفحه هنگام استفاده از ویژگی defer برای اسکریپت خارجی در حالت Defer همانطور که در تصویر ملاحظه می‌کنید، اسکریپت خارجی همزمان با لود صفحه دریافت می‌شود، ولی اجرای آن به انتهای این فرایند سپرده می‌شود. بنابراین مشکل قبلی‌ای که با Async داشتیم، با ویژگی Defer رفع می‌شود.بالاخره Async یا Defer؟حالا به این سوال متداول می‌رسیم که بالاخره Async بهتر است یا Defer؟به طور کلی ویژگی Defer در اکثر موارد سریع‌ترین راه برای لود محتوای صفحه در مرورگر است. ولی با توضیحاتی که داده شد، باید روشن شده باشد که اساسا طرح مساله به این شکل چندان درست نیست. در اینجا با دو ویژگی متفاوت و در نوع خود کاربردی طرف هستیم که اگر در جای درست استفاده شوند، نتیجه مطلوب می‌دهند و در غیر اینصورت نتیجه معکوس. بنابراین مساله نه الزاما بر سر انتخاب بین این یا آن ویژگی، بلکه یافتن ترکیب بهینه از هر دو است. مثلا در یک صفحه واحد می‌توان ضمن اعمال ویژگی Async روی همه اسکریپت‌ها، استثنائا فقط به تعدادی از آن‌ها ویژگی Defer داد یا برعکس.افزونه‌های مختلف بهینه‌سازی به شما کمک می‌کنند که خیلی ساده و به روش آزمون و خطا پی ببرید که ویژگی Async بیشتر مناسب سایت شماست یا ویژگی Defer (چون اعمال یک ویژگی روی اسکریپت‌های خارجی می‌تواند باعث بهبود سرعت، ولی در عین حال از کار افتادن بخشی از عملکردهای سایت شود). پس این همیشه و در همه موارد کافی نیست. قدم بعدی اینست که داده‌های سایت‌هایی مثل GTmetrix را آنالیز کنید؛ تشخیص بدهید که کدام فایل‌های ضروری را علیرغم Render Blocking نگه دارید و کدامیک را حذف کنید تا تعدادشان به حداقل برسد؛ کدام فایل جاوااسکریپت را از یک ویژگی خاص (Async یا Defer) مستثنا کنید و... در چنین مواردی حتی شاید بطلبد که قدری کدنویسی سایت خود را هم اصلاح کنید.وندا نوژن