بهینهسازی کدهای جاوا اسکریپت در سال ۲۰۱۸ — راهنمای جامع (بخش اول)
ساخت سایتهای تعاملی به معنی ارسال کدهای جاوا اسکریپت به کاربران است، که در اغلب موارد حجم بالایی از این کدها میبایست ارسال شوند. آیا تاکنون با صفحه موبایلی مواجه شدهاید که گویا صرفاً برای این بارگذاری شده است که شما بر روی یک لینک بزنید یا این که صفحه را اسکرول میکنید و بعد هیچ اتفاقی نمیافتد؟ بایت به بایت جاوا اسکریپت همچنان جزو پرهزینهترین منابعی است که به گوشیهای تلفن همراه ارسال میشود، زیرا میتواند به روشهای مختلف موجب تأخیر در تعاملپذیری وبسایت شود.
در این مقاله به بررسی برخی راهبردها میپردازیم که با استفاده از آنها میتوانید کد جاوا اسکریپت را به طرز کارآمدتری به کاربر تحویل دهید و در عین حال تجربه کاربری مطلوبی را به کاربر خود عرضه کنید.
tl;dr (این بخش طولانی است و عدم مطالعه آن لطمهای به کلیت مقاله نمیزند.)
- برای این که بارگذاری وبسایت سریع باشد، تنها آن دسته از کدهای جاوا اسکریپت را لود کنید که در صفحه کنونی مورد نیاز است. اولویتبندی نیازهای کاربر و بارگذاری با تأخیر (lazy-load) بقیه کدها به همراه استفاده از تکنیک افراز کد (Code Splitting) به این منظور راهگشا است. بدین ترتیب احتمال بارگذاری و تعاملپذیری سریع صفحه بیشترمی شود. استکهایی که به طور پیشفرض از افراز کد مبتنی بر مسیر استفاده میکنند، آینده این فناوری را تعیین میکنند.
- از بودجهبندی عملکردی استفاده کنید و یاد بگیرید که در محدوده این بودجهبندی عمل کنید. در مورد کاربرد موبایل، هدفگذاری بودجه جاوا اسکریپت کمتر از 170 کیلوبایت در حالت کوچک شده (minified)/ فشرده، عدد مناسبی است. با این حال همین کد در حالت غیر فشرده در حدود 0.7 مگابایت فضا اشغال میکند. بودجهبندی برای موفقیت ضروری است؛ ولی به تنهایی نمیتواند معجزه خاصی انجام دهد. فرهنگ تیمی، ساختار و قانونمداری نیز مهم هستند. ساخت کد بدون بودجهبندی باعث افت عملکرد و از دست رفتن کارایی میشود.
- یاد بگیرید که چگونه بستههای کد جاوا اسکریپت خود را بازرسی کرده و آنها را خلاصهتر کنید. موارد زیادی هستند که شما یک کتابخانه کامل را به کاربر ارسال میکنید، اما تنها بخش کوچکی از آن مورد نیاز است. از جمله بخشهای زائد، پلیفیل ها (polyfills) برای مرورگرهایی که نیاز ندارند و یا کدهای تکراری هستند.
- هر تعامل آغاز یک فرایند جدید «زمان مورد نیاز برای تعاملپذیری» (Time-to-Interactive) است؛ از این رو باید در این چارچوب به فکر بهینهسازی باشید. اندازه کد انتقالی برای شبکههای موبایل قدیمی و زمان تجزیه کد جاوا اسکریپت در دستگاههایی که دچار ضعف پردازش گرافیکی هستند، بسیار حائز اهمیت هستند.
- اگر کد جاوا اسکریپت سمت کاربر، کمکی به تجربه کاربری نمیکند، باید از خود پرسید واقعاً وجود آن الزامی دارد. در این موارد HTML رندر شده در سمت سرور ممکن است بسیار سریع باشد. سعی کنید استفاده از چارچوبهای سمت کاربر را به صفحاتی محدود کنید که واقعاً مورد نیاز هستند. رندر کردن در سمت سرور و رندر کردن در سمت کلاینت اگر به درستی اجرا نشوند، هر دو میتوانند نتایج وخیمی به بار بیاورند.
وب مملو از «تجربه» کاربر شده است
وقتی کاربران وارد وبسایت شما میشوند، احتمالاً فایلهای زیادی را برای آنها میفرستید که بسیاری از آنها اسکریپت هستند.
از دیدگاه یک مرورگر وب این مسئله تا حدودی شبیه تصویر زیر است:
با این که همه ما جاوا اسکریپت را دوست داریم؛ اما در اغلب موارد یکی از پرهزینهترین بخشهای سایت محسوب میشود. در ادامه توضیح خواهیم داد که چرا این وضعیت میتواند به یک مشکل عمده تبدیل شود.
امروزه یک صفحه وب معمولی در حدود 350 کیلوبایت کد جاوا اسکریپت کوچکشده و فشردهشده را در خود حمل میکند. اگر این کد از حالت فشرده خارج شود، مرورگر مجبور خواهد بود تا بیش از 1 مگابایت اسکریپت را نیز پردازش کند.
نکته: اگر نگران این هستید که بستههای جاوا اسکریپت شما در میزان زمان مورد نیاز کاربر برای تعامل با وبسایت تأخیر ایجاد میکنند، lighthouse را بررسی کنید.
تجربه نشان میدهد که این حجم از کد جاوا اسکریپت به بیش از 14 ثانیه زمان برای پردازش بر روی گوشیهای تلفن همراه نیاز دارند. بخش بزرگی از این مسئله مربوط به زمان مورد نیاز به دانلود کد روی شبکه تلفن همراه و سپس پردازش آن بر روی پردازنده موبایل است. در ادامه نگاهی به شبکههای تلفن همراه خواهیم داشت.
نمودار فوق از OpenSignal نشان میدهد که در کدام کشورهای جهان شبکههای 4G در دسترس هستند و میانگین سرعت اتصال در هر کشور چه مقدار است. همان طور که میبینید بسیاری از کشورها همچنان سرعتهای اتصال پایینتری نسبت به آن چه تصور میکنیم، دارند. باید توجه داشت که علاوه بر زمانی که برای دانلود آن 350 کیلوبایت که قبلاً بیان کردیم مورد نیاز است، در واقعیت وقتی به برخی وبسایتهای محبوب نگاه میکنیم حجم اسکریپتی که دانلود میشود، بسیار بالاتر از این مقدار است:
این حجم از کد را هم در پلتفرم موبایل و هم دسکتاپ شاهد هستیم؛ به طوری که وبسایتهای مختلف چندین مگابایت کد را به مرورگرها ارسال میکنند و سپس این مرورگرها باید این کد را پردازش کنند. سؤالی که در اینجا پیش میآید این است که آیا این حجم از کد جاوا اسکریپت معقول است؟
جاوا اسکریپت هزینه دارد
نکته: اگر در یک صفحه وب حجم بالایی از کد جاوا اسکریپت ارسال شود، میتوان از افراز کد برای تقسیم آن به بستههای مختلف و یا کاهش payload جاوا اسکریپت با استفاده از تکنیک Tree shaking استفاده کرد. امروزه سایتها غالباً موارد زیر را در بستههای جاوا اسکریپت ارسال میکنند:
- یک فریمورک سمت کاربر یا کتابخانه UI
- یک راهحل برای مدیریت وضعیت (مانند Redux)
- پلیفیل ها (که مرورگرهای مدرن غالباً به آنها نیاز ندارند)
- کتابخانههای کامل و یا مواردی که آنها استفاده میکنند (مانند lodash, Moment + locales).
- مجموعهای از اجزای UI (دکمهها، هدرها، ساید بارها و ...)
همه اینها به کد اصلی اضافه میشوند و هر چه این کد حجیمتر باشد، بارگذاری صفحه زمان بیشتری طول میکشد. بارگذاری یک صفحه مانند یک نوار فیلم است که سه لحظه کلیدی دارد: لحظه نمایش، لحظه مفید بودن و لحظه قابل استفاده بودن.
- نمایش همان لحظهای است که میتوانید محتوایی را در صفحه نمایش دهید (آیا ناوبری آغاز شده است؟ آیا سرور شروع به پاسخ دادن کرده است؟)
- مفید بودن لحظهای است که متن یا محتوایی را نمایش دادهاید که کاربر از آن ارزشی میگیرد و میتواند با آن مشغول شود.
- و در نهایت قابلیت استفاده زمانی آغاز میشود که کاربر بتواند به طور معناداری با صفحه وب تعامل کرده و عملی بر روی آن انجام دهد.
از واژه تعامل قبلاً نیز بارها استفاده کردیم؛ اما واقعاً منظور ما از تعامل چیست؟
برای این که صفحهای تعاملپذیر باشد، میبایست قابلیت پاسخدهی سریع به ورودی کاربر را داشته باشد. یک payload کوچک جاوا اسکریپت میتواند تضمین کند که این مسئله به سرعت اتفاق میافتد. چه کاربر روی یک لینک کلیک کند یا یک صفحه را اسکرول بکند، در هر حال میبایست ببیند که در پاسخ به اقدامش واکنشی در عمل رخ میدهد. تجربهای که نتواند این حس را به کاربر منتقل کند، باعث ناراحتی او میشود.
یکی از محلهایی که این مسئله به وفور رخ میدهد، زمانی است که کدی در سمت سرور قرار است تجربه کاربر را رندر کرده و سپس یک دسته کد جاوا اسکریپت را پس از تکمیل شدن رابط کاربری به مرورگر ارسال کند (اتصال کنترلرهای رویداد و رفتارهای دیگر)
وقتی یک مرورگر بسیاری از این رویدادها را اجرا کند، این احتمال هست که برخی از آنها وارد همان تردی شوند که ورودی کاربر را مدیریت میکند. این ترد به نام ترد اصلی (main thread) نامیده میشود. بارگذاری مقادیر بالایی از کد جاوا اسکریپت در ترد اصلی (از طریق <script> و یا غیره) یک مشکل محسوب میشود. واکشی جاوا اسکریپت به درون یک web Worker یا کش کردن از طریق Service Worker این تأثیر منفی را بر روی time-to-interactive ندارد.
مثالی از این وضعیت زمانی است که کاربر بر روی بخشی از UI میزند. به طور معمول کاربران میتوانند یک چک باکس را انتخاب کنند یا روی یک لینک کلیک کنند و یا هر چیزی که به درستی کار میکند. اما اگر وضعیت مسدودسازی ترد اصلی را شبیهسازی کنیم، میبینیم که در این حالت هیچ اتفاقی رخ نمیدهد. کاربران دیگر نمیتوانند آن چک باکس را انتخاب کنند یا روی لینک کلیک کنند، چون ترد اصلی مسدود شده است. میبایست تا حد امکان از مسدود شدن ترد اصلی خودداری کرد. تیمهای مختلفی هستند که از تأثیر جاوا اسکریپت بر روی قابلیت تعامل انواع مختلفی از وبسایتها رنج میبرند.
وجود کد زیاد جاوا اسکریپت در ترد اصلی میتواند منجر به تأخیر در تعاملپذیری شود و این مسئله برای بسیاری از شرکتها یک چالش به حساب میآید. در بخش بالا چند مثال از جستجوی گوگل را میبینید که میتوانید در بخشهای مختلف UI ضربه بزنید؛ ولی اگر سایت کد جاوا اسکریپت زیادی را ارسال کرده باشد، پیش از این که عملی واقعاً رخ بدهد باید زمانی را منتظر بمانید. این مسئله باعث میشود که کاربر حس بدی پیدا کند و بدین دلیل میبایست همه اجزای UI در اولین فرصت ممکن به حالت تعاملپذیر در آیند.
با اندازهگیری معیار زمان تعاملپذیری در وبسایت اخبار گوگل بر روی موبایل میبینیم که بین یک گوشی پیشرفته با زمانی در حدود 7 ثانیه و یک گوشی ارزانقیمت با زمانی در حدود 55 ثانیه، اختلاف زمان زیادی وجود دارد. بنابراین هدف مناسب برای تعاملپذیری کدام است؟
هنگامی که از «زمان تعاملپذیری» صحبت میکنیم، حس میکنیم که نسخه اولیه وبسایت میبایست در یک اتصال کُند 3G دستکم در طی 5 ثانیه بر روی یک گوشی متوسط به وضعیت تعاملپذیر برسد. ممکن است بگویید اما همه کاربران ما بر روی شبکههای سریع و گوشیهای تلفن همراه پیشرفته هستند. سؤال این است که آیا اشتباه نمیکنید؟ شما ممکن است از اینترنت سریع یک کافیشاپ استفاده کنید؛ اما در عمل تنها به سرعتهای 2G یا 3G برسید. این تغییرات مهم هستند.
چه کسانی توانستهاند حجم انتقال کد جاوا اسکریپت و معیار زمان تعاملپذیری خود را کاهش دهند؟
- پینترست حجم کد جاوا اسکریپت خود را از 2.5 مگابایت به کمتر از 200 کیلوبایت کاهش داده است و زمان تعاملپذیری از 23 ثانیه به 5.6 ثانیه کاهش یافته است. بدین ترتیب درآمد 44 درصد، میزان ثبتنام 753 درصد و کاربران فعال هفتگی در نسخه موبایل وبسایت تا 103 درصد افزایش یافتهاند.
- AutoTrender حجم کد جاوا اسکریپت را به میزان 56 درصد و زمان تعاملپذیری صفحهها را تا 50 درصد کاهش داده است.
- Nikkei حجم کد جاوا اسکریپت را به میزان 43 درصد و زمان تعاملپذیری را تا 14 ثانیه بهبود بخشیده است.
تلاش کنید نسخه موبایل انعطافپذیرتری از وبسایت را طراحی کنید که تکیه زیادی بر روی payload های جاوا اسکریپت حجیم نداشته باشد. تعاملپذیری از مسائل زیادی تأثیر میپذیرد. تعاملپذیری میتواند از سرعت طرح اینترنتی یک کاربر، سرعت وایفای یک کافیشاپ و یا قطع و وصل مکرر ارتباط اینترنتی تأثیر بپذیرد.
وقتی مشکل ارتباطی پیش میآید و شما هنوز کدهای جاوا اسکریپت زیادی دارید که منتظر پردازش هستند، ممکن است کاربران صبر نکنند تا همه چیز به طور کامل بارگذاری شود و یا اگر وبسایت به درستی بارگذاری نشود ممکن است مدت زیادی منتظر بمانند تا بتوانند با هر یکی از اجزای صفحه تعامل داشته باشند. اما ارسال کد کمتر جاوا اسکریپت همه این مشکلات را مرتفع میسازد.
چرا جاوا اسکریپت چنین پرهزینه است؟
برای این که توضیح دهیم چرا جاوا اسکریپت باید چنین پرهزینه باشد، ابتدا باید توضیح دهیم که وقتی یک محتوا را به مرورگری میفرستید چه اتفاقی رخ میدهد. در این وضعیت کاربر یک URL را در نوار آدرس مرورگر خود وارد میکند:
یک درخواست به سرور ارسال میشود که قدری محتوای نشانهگذاری شده (markup) باز میگرداند. سپس مرورگر این محتوای نشانهگذاری شده را پردازش میکند و درمییابد که حاوی کدهای CSS، جاوا اسکریپت و تصاویر مورد نیاز است. در این زمان مرورگر باید همه منابع مورد نیاز را واکشی کرده و مورد پردازش قرار دهد. سناریوی فوق توصیفی دقیق از آن چیزی است که وقتی هر گونه محتوایی به یک مرورگر مانند کروم ارسال میشود انجام مییابد.
در این فرایند یکی از چالشها آن است که جاوا اسکریپت تبدیل به یک گلوگاه میشود. منظور از گلوگاه چیزی است که باعث کندتر شدن اجزای دیگر میشود. معمولاً ما انتظار داریم که تصاویر وبسایت به سرعت روی گوشی ظاهر شود و سپس بتوان با آن تعامل کرد. اما اگر جاوا اسکریپت یک گلوگاه باشد، در نهایت شما با صفحهای مواجه خواهید شد که فقط میتوانید تماشایش کنید و هیچ تعاملی نمیپذیرد.
برای داشتن یک تجربه مدرن میبایست تلاش کنیم که دیگر جاوا اسکریپت یک گلوگاه نباشد. یکی از نکاتی که همواره در این زمینه باید به خاطر داشته باشید، این است که اگر میخواهید جاوا اسکریپت سریع باشد، باید آن را به سرعت دانلود، تجزیه، کامپایل و اجرا کنید. این بدان معنی است که انتقال در شبکه و سمت پردازش اسکریپتها نیز باید سریع باشد. اگر زمان زیادی را صرف تجزیه و کامپایل کردن اسکریپت در موتور جاوا اسکریپت بکنید این تأخیر بر روی سرعت تعاملپذیری کاربر با صفحه وب تأثیر میگذارد.
بخش نارنجی نشان دهنده همه زمان صرف شده برای تجزیه جاوا اسکریپت است که وبسایتهای محبوب ارسال میکنند. نوارهای زرد، زمان صرف شده برای کامپایل این اسکریپتها را نشان میدهند و این دو با هم تا سقف 30 درصد از زمان پردازش جاوا اسکریپت صفحه را تشکیل میدهند که یک هزینه بالا محسوب میشود.
در نسخه 66 کروم، موتور V8 کد را در ترد پسزمینه کامپایل میکند و بدین ترتیب زمان کامپایل تا 20 درصد کاهش یافته است. اما تجزیه و کامپایل همچنان بسیار پرهزینه است و به ندرت میتوان اسکریپت بزرگی را دید که حتی در صورتی که در ترد کامپایل شده باشد، در عمل در زیر 50 میلیثانیه اجرا شود. نکته دیگری که باید به خاطر بسپارید این است که وقتی از جاوا اسکریپت صحبت میکنیم، مسئله هزینه متفاوت است. یک اسکریپت 200 کیلوبایتی و یک تصویر 200 کیلوبایتی هزینههای بسیار متفاوتی دارند.
گرچه برای دانلود دو مورد فوق ممکن است زمان یکسانی مورد نیاز باشد، اما وقتی بحث پردازش پیش میآید، هزینهها بسیار متفاوت هستند. یک تصویر JPEG باید رمزگشایی شود، rasterize شود تا بر روی صفحه نمایش یابد. یک بسته جاوا اسکریپت باید دانلود شود و سپس تجزیه و کامپایل شده و اجرا شود. گامهای دیگری نیز وجود دارند که موتور جاوا اسکریپت باید انجام دهد. صرفاً باید توجه داشته باشید که هزینههای این دو معادل هم نیستند. یکی از دلایل این که باید به میزان حجم کد اهمیت بدهیم پلتفرم موبایل است. در بخش دوم این راهنما به بررسی تاثیر پلتفرمهای مختلف موبایل و تاثیر آنها بر بهینهسازی کد خواهیم پرداخت.
اگر این نوشته مورد توجه شما قرار گرفته است، پیشنهاد میکنیم موارد زیر را نیز ملاحظه کنید:
- جاوا اسکریپت چیست؟
- آموزش جاوا اسکریپت (JavaScript)
- ۱۰ کتابخانه و فریمورک جاوا اسکریپت که باید آنها را بشناسید
- مجموعه آموزش های پروژه محور برنامه نویسی
- آموزش تعریف توابع در جاوا اسکریپت (JavaScript)
- طراحی و برنامه نویسی وب
==