امروزه در برنامههای تحت وب، بارگذاری فایلهای جاوااسکریپت صفحات، یکی از چالشهای بزرگ در عملکرد، کارآیی و سرعت اجرای صفحات وب به شمار میآید. حال اینکه توسعه اپلیکیشنهای single page و استفاده از کتابخانههای حجیم جاوااسکریپتی، حجم این سری فایلها را بیشتر و بیشتر نیز میکند.
در شرایطی خاص، تگ script باعث میشود که مرورگر برای مدت زمانی متوقف شود و فایلهای جاوااسکریپت را بارگذاری و اجرا نماید. در این مواقع مرورگر از انجام عملیات دیگری منع شده و شروع به اعمال فایل جاوااسکریپت در حال بارگذاری در محتوای صفحهی بار شده میکند. این نگارش و اعمال میتواند سبب ویرایش یک element و یا تغییر DOM یا ارجاعی به یک URL دیگر شود. به این منظور، بهترین و رایجترین کار این است که تگهای script را به انتهای صفحه و پیش از تگ body منتقل کنیم. با این حال نیز ممکن است که مرورگر برای چند ثانیه منتظر دریافت پاسخهای اسکریپتهای انتهای صفحه بماند، اما این امر چندان قابل توجه نیست؛ به این دلیل که غالب استایلها و content صفحه بارگذاری شدهاند. با این وجود، این راهکار برای صفحات وب کنونی که ممکن است شامل محتوای یک یا چندین مگابایتی باشند، کافی نیست.
در این مواقع برخی از کد نویسها از روشهایی مانند inject کردن تگ script به صورت Ajax استفاده میکنند که این روشها از block شدن صفحه جلوگیری میکند، اما با این حال این روشها نیز چالشهای خاص خود مانند نوشتن کدهای اضافی برای هر اسکریپت و تستهای مرتبط برای اطمینان از بار شدن و اجرای صحیح اسکریپتها در موقعیت مناسب را دارند که ممکن است روند کد نویسی با استفاده از کتابخانههای third-party را بسیار طولانی کند.
برای حل این چالش خرسندم که تکنیکی را که به صورت built-in در HTML5 وجود دارد، به شما معرفی کنم.
استفاده از defer Attribute
این Attribute اگر درون هر تگ script ایی نوشته شود، آن فایل در هنگام بارگذاری فایلها و ساختن صفحه، نادیده گرفته میشود و پس از اتمام پروسه، این فایل شروع به بارگذاری شدن میکند. در حقیقت در این حین در مرورگر همانند تمامی عملیاتهای Lazy Loading به صورت ضمنی یک promise ساخته میشود. البته گفتنی است که این نوع بارگذاری نباید شامل فایلهای جاوا اسکریپتی باشد که شامل عملیاتی مانند document.write و یا تغییرات DOM هستند.
<script src="file.js" defer></script>
مرورگر تمامی فایلهای شامل defer Attribute را بدون توقف پردازشهای صفحه، به صورت موازی بارگذاری مینماید. اما اینکه این ویژگی از چه زمانی در مرورگرها وجود داشته؟ باید گفت که تقریبا 12 سال از عمر آن میگذرد. تقریبا از نسخهی IE4 (^_^). البته این نکته گفتنی است هنگامی که شما از این Attribute استفاده میکنید، این تضمین وجود دارد که تمامی این اسکریپتها اجرا میشوند، اما اینکه کدامیک در چه زمانی بارگذاری و اجرا میشوند، کاملا نامشخص است. از نظر تئوری، عملیات بارگذاری پس از ویرایش DOM و کمی پیش از فراخوانی رخداد DOMContentLodaded صورت میگیرد. اما در عمل، این عملیات به مرورگر و سیستمعامل نیز وابسته است.
استفاده از async Attribute
این Attribute در HTML5 معرفی شد و به نوعی کامل کننده و منسوخ کنندهی defer میباشد.
<script src="file.js" async></script>
به طور کلی میتوان گفت که عملکرد async و defer یکسان میباشند. البته تفاوت اصلی این دو سینتکس، در زمان اجرای اسکریپتهای بار شده میباشد. در async عملیات execution، در اولین فرصتی که پس از تکمیل دریافت فایل ممکن است، صورت میگیرد. به سه تصویر زیر توجه کنید:
تصویر فوق یک سناریوی سادهی بارگذاری صفحهی html را به همراه یک فایل جاوااسکریپت با تگ script ساده را نمایش میدهد. همانطور که ملاحظه میکنید، در لحظهای که فایل اسکریپت شروع به دانلود شدن میکند (قسمت بنفش)، عملیات parse صفحه متوقف شده تا زمانی که فایل دانلود و اجرا شود (قسمت قرمز). پس از آن دوباره عملیات parsing از سر گرفته میشود. این عملیات به همراه تگ script ساده صورت گرفته است. حال در تصویر بعد قصد داریم که همین سناریو را به کمک defer Attribute بررسی کنیم:
همانطور که ملاحظه میکنید به کمک defer، شروع عملیات دانلود فایل اسکریپت، خللی در عملیات html parse ایجاد نمیکند و این دو عملیات به صورت موازی میتوانند اجرا شوند. پس از دریافت فایل اسکریپت، این فایل مستقیما اجرا نمیشود و لزوما باید پس از عملیات parsing صورت پذیرد.
و اما تصویر زیر، سناریوی فوق را به همراه async attribute نمایش میدهد:
در این حالت عملیات دریافت فایل اسکریپت همانند defer به صورت موازی اجرا میشود. اما تفاوتی که در این قسمت و در async وجود دارد، زمان اجرا شدن فایلهای اسکریپت است. همانطور که ملاحظه میکنید دقیقا پس از دریافت فایل، اسکریپت ما در اجراست و پس از اجرای کامل، دوباره عملیات parsing ادامه مییابد. در حقیقت اسکریپتهای با async attribute با فراخوانی رخداد onload شروع به اجرا میکنند. جهت استفادهی از async، خیالتان راحت باشد؛ با توجه به این منبع، تقریبا تمام مرورگرها از این ویژگی پشتیبانی میکنند.