مقدمه
HTML5 ابزارهای عالی برای بهبود ظاهر بصری برنامه های کاربردی وب به ما می دهد. این امر به ویژه در حوزه انیمیشن ها صادق است. با این حال، با این قدرت جدید چالش های جدیدی نیز به وجود می آید. در واقع این چالشها واقعاً جدید نیستند و گاهی اوقات ممکن است منطقی باشد که از همسایه میز خود، برنامهنویس Flash، بپرسید که چگونه در گذشته بر موارد مشابه غلبه کرده است.
به هر حال، وقتی شما در انیمیشن کار می کنید، بسیار مهم است که کاربران این انیمیشن ها را روان و روان درک کنند. چیزی که ما باید بدانیم این است که نرمی در انیمیشن ها واقعاً با افزایش فریم در ثانیه فراتر از هر آستانه شناختی ایجاد نمی شود. مغز ما متأسفانه باهوش تر از این حرف هاست. چیزی که یاد خواهید گرفت این است که 30 فریم واقعی انیمیشن (فریم در ثانیه) بسیار بهتر از 60 فریم در ثانیه است که فقط چند فریم در وسط افت می کند. مردم از تنبلی متنفرند.
این مقاله سعی میکند ابزارها و تکنیکهایی را در اختیار شما بگذارد تا روی بهبود تجربه اپلیکیشن خود کار کنید.
استراتژی
به هیچ وجه نمی خواهیم شما را از ساختن برنامه های بصری عالی و خیره کننده با HTML5 منصرف کنیم.
سپس وقتی متوجه شدید که عملکرد می تواند کمی بهتر باشد، به اینجا برگردید و در مورد چگونگی بهبود عناصر برنامه خود مطالعه کنید. البته میتواند در وهله اول به انجام درست برخی کارها کمک کند، اما هرگز اجازه ندهید که این کارها مانع از کارآمدی شما شود.
Visual fidelity++ با HTML5
شتاب سخت افزاری
شتاب سخت افزاری یک نقطه عطف مهم برای عملکرد کلی رندر در مرورگر است. طرح کلی این است که وظایفی را که در غیر این صورت توسط CPU اصلی محاسبه میشوند، به واحد پردازش گرافیکی (GPU) در آداپتور گرافیک رایانهتان بارگذاری کنید. این می تواند دستاوردهای عملکرد گسترده ای داشته باشد و همچنین می تواند مصرف منابع را در دستگاه های تلفن همراه کاهش دهد.
این جنبه های سند شما می تواند توسط GPU تسریع شود
- ترکیب چیدمان عمومی
- انتقال CSS3
- CSS3 3D تبدیل می شود
- طراحی بوم
- طراحی سه بعدی WebGL
در حالی که تسریع بوم و WebGL ویژگیهای هدف خاصی هستند که ممکن است برای برنامه خاص شما اعمال نشوند، سه جنبه اول تقریباً به هر برنامه کمک میکند تا سریعتر شود.
چه چیزی را می توان تسریع کرد؟
شتاب GPU با بارگذاری وظایف کاملاً تعریف شده و خاص به سخت افزار با هدف خاص کار می کند. طرح کلی این است که سند شما به چندین "لایه" تقسیم می شود که نسبت به جنبه های صفحه شما که تسریع می شود تغییر نمی کند. این لایه ها با استفاده از خط لوله رندر سنتی رندر می شوند. سپس از GPU برای ترکیب لایهها در یک صفحه استفاده میشود و «افکتهایی» را اعمال میکند که میتوانند در پرواز تسریع شوند. یک نتیجه احتمالی این است که یک شی که روی صفحه متحرک است نیازی به یک "relayout" صفحه نداشته باشد در حالی که انیمیشن اتفاق می افتد.
چیزی که باید از آن حذف کنید این است که باید کاری کنید که موتور رندر تشخیص دهد که چه زمانی می تواند جادوی شتاب GPU خود را اعمال کند. به مثال زیر توجه کنید:
در حالی که این کار می کند، مرورگر واقعاً نمی داند که شما چیزی را اجرا می کنید که قرار است توسط یک انسان به عنوان انیمیشن صاف درک شود. در نظر بگیرید که چه اتفاقی میافتد وقتی به همان ظاهر بصری با استفاده از انتقالهای CSS3 دست پیدا میکنید:
نحوه پیاده سازی این انیمیشن توسط مرورگر کاملاً از دید توسعه دهنده پنهان است. این به نوبه خود به این معنی است که مرورگر می تواند ترفندهایی مانند شتاب GPU را برای رسیدن به هدف تعریف شده اعمال کند.
دو پرچم خط فرمان مفید برای کروم برای کمک به رفع اشکال شتاب GPU وجود دارد:
-
--show-composited-layer-borders
یک حاشیه قرمز رنگ اطراف عناصری را نشان می دهد که در سطح GPU دستکاری می شوند. برای تأیید اینکه دستکاری های شما در لایه GPU رخ می دهد خوب است. -
--show-paint-rects
تمام تغییرات غیر GPU رنگ شده اند و این یک حاشیه روشن در اطراف همه مناطقی که دوباره رنگ شده است ایجاد می کند. شما می توانید مرورگر را در حال بهینه سازی مناطق رنگ آمیزی مشاهده کنید.
سافاری دارای پرچمهای زمان اجرا مشابهی است که در اینجا توضیح داده شده است .
CSS3 Transitions
CSS Transitions انیمیشن سبک را برای همه بی اهمیت می کند، اما آنها همچنین یک ویژگی عملکرد هوشمند هستند. از آنجایی که یک انتقال CSS توسط مرورگر مدیریت می شود، وفاداری انیمیشن آن را می توان تا حد زیادی بهبود بخشید و در بسیاری از موارد سخت افزار را تسریع کرد. در حال حاضر WebKit (Chrome، Safari، iOS) تغییرات سخت افزاری CSS را تسریع کرده است، اما به سرعت به مرورگرها و پلتفرم های دیگر می آید.
میتوانید از رویدادهای transitionEnd
برای اسکریپت کردن آن در ترکیبهای قدرتمند استفاده کنید، اگرچه در حال حاضر، ثبت همه رویدادهای پایان انتقال پشتیبانیشده به معنای تماشای webkitTransitionEnd transitionend oTransitionEnd
است.
اکنون بسیاری از کتابخانهها APIهای انیمیشنی را معرفی کردهاند که در صورت وجود از انتقالها استفاده میکنند و در غیر این صورت به انیمیشنهای استاندارد DOM بازمیگردند. scripty2 , YUI Transition , jQuery anime بهبود یافته .
ترجمه CSS3
من مطمئن هستم که قبلاً متوجه شده اید که موقعیت x/y یک عنصر را در سراسر صفحه متحرک کرده اید. احتمالاً ویژگی های سمت چپ و بالای سبک درون خطی را دستکاری کرده اید. با تبدیل های دو بعدی، می توانیم از قابلیت translate()
برای تکرار این رفتار استفاده کنیم.
ما می توانیم این را با انیمیشن DOM ترکیب کنیم تا از بهترین چیز ممکن استفاده کنیم
<div style="position:relative; height:120px;" class="hwaccel">
<div style="padding:5px; width:100px; height:100px; background:papayaWhip;
position:absolute;" id="box">
</div>
</div>
<script>
document.querySelector('#box').addEventListener('click', moveIt, false);
function moveIt(evt) {
var elem = evt.target;
if (Modernizr.csstransforms && Modernizr.csstransitions) {
// vendor prefixes omitted here for brevity
elem.style.transition = 'all 3s ease-out';
elem.style.transform = 'translateX(600px)';
} else {
// if an older browser, fall back to jQuery animate
jQuery(elem).animate({ 'left': '600px'}, 3000);
}
}
</script>
ما از Modernizr برای تست ویژگی برای CSS 2D Transforms و CSS Transitions استفاده می کنیم، اگر چنین است، ما از translate برای تغییر موقعیت استفاده می کنیم. اگر این انیمیشن با استفاده از یک انتقال متحرک باشد، احتمال زیادی وجود دارد که مرورگر بتواند سخت افزار آن را تسریع کند. برای اینکه مرورگر را در جهت درست فشار دهیم، از "گلوله جادویی CSS" از بالا استفاده می کنیم.
اگر مرورگر ما توانایی کمتری دارد، برای جابجایی عنصر خود به جی کوئری بازگشته ایم. شما می توانید پلاگین jQuery Transform polyfill توسط Louis-Remi Babe را انتخاب کنید تا کل این کار به صورت خودکار انجام شود.
window.requestAnimationFrame
requestAnimationFrame
توسط Mozilla معرفی شد و توسط WebKit تکرار شد و هدف آن ارائه یک API بومی برای اجرای انیمیشنها، خواه مبتنی بر DOM/CSS یا <canvas>
یا WebGL باشد. مرورگر میتواند انیمیشنهای همزمان را با هم در یک چرخه مجدد و رنگآمیزی بهینهسازی کند، که منجر به انیمیشنهایی با وفاداری بالاتر میشود. به عنوان مثال، انیمیشن های مبتنی بر JS که با انتقال CSS یا SVG SMIL همگام شده اند. بهعلاوه، اگر حلقه انیمیشن را در برگهای اجرا میکنید که قابل مشاهده نیست، مرورگر آن را در حال اجرا نگه نمیدارد ، که به معنای استفاده کمتر از CPU، GPU و حافظه است که منجر به عمر باتری بسیار بیشتر میشود.
برای جزئیات بیشتر در مورد چگونگی و چرایی استفاده از requestAnimationFrame
، مقاله Paul Irish requestAnimationFrame برای انیمیشن هوشمند را مشاهده کنید.
پروفایل کردن
هنگامی که متوجه شدید که سرعت برنامه شما می تواند بهبود یابد، زمان آن فرا رسیده است که به نمایه سازی بپردازید تا دریابید که در کجا بهینه سازی می تواند بیشترین سود را داشته باشد. بهینه سازی ها اغلب تأثیر منفی بر قابلیت نگهداری کد منبع شما خواهند داشت و بنابراین فقط در صورت لزوم باید اعمال شوند. نمایه سازی به شما می گوید که کدام بخش از کد شما با بهبود عملکرد آنها بیشترین مزیت را دارد.
پروفایل جاوا اسکریپت
نمایه سازهای جاوا اسکریپت با اندازه گیری زمان لازم برای اجرای هر تابع از ابتدا تا انتهای آن، یک نمای کلی از عملکرد برنامه شما در سطح عملکرد جاوا اسکریپت به شما ارائه می دهند.
زمان اجرای ناخالص یک تابع زمان کلی است که برای اجرای آن از بالا به پایین طول می کشد. زمان اجرای خالص، زمان اجرای ناخالص منهای زمانی است که برای اجرای توابع فراخوانی شده از تابع صرف شده است.
برخی از توابع بیشتر از بقیه فراخوانی می شوند. پروفیلها معمولاً زمان لازم برای اجرای همه فراخوانها و همچنین میانگین و حداقل و حداکثر زمان اجرا را به شما میدهند.
برای جزئیات بیشتر، اسناد Chrome Dev Tools در مورد نمایه سازی را بررسی کنید.
DOM
عملکرد جاوا اسکریپت تأثیر زیادی بر میزان روان و پاسخگو بودن برنامه شما دارد. درک این نکته مهم است که در حالی که پروفایلکنندگان جاوا اسکریپت زمان اجرای جاوا اسکریپت شما را اندازهگیری میکنند، آنها بهطور غیرمستقیم زمان صرف شده برای انجام عملیات DOM را نیز اندازهگیری میکنند. این عملیات DOM اغلب در قلب مشکلات عملکرد شما قرار دارند.
function drawArray(array) {
for(var i = 0; i < array.length; i++) {
document.getElementById('test').innerHTML += array[i]; // No good :(
}
}
به عنوان مثال در کد بالا تقریباً هیچ زمانی برای اجرای جاوا اسکریپت واقعی صرف نمی شود. هنوز هم بسیار محتمل است که تابع drawArray در نمایههای شما نمایش داده شود، زیرا در حال تعامل با DOM به شیوهای بسیار بیهوده است.
نکات و ترفندها
توابع ناشناس
نمایه کردن توابع ناشناس آسان نیست زیرا آنها ذاتاً نامی ندارند که تحت آن بتوانند در نمایه ساز نشان داده شوند. دو راه برای حل این مشکل وجود دارد:
$('.stuff').each(function() { ... });
بازنویسی به:
$('.stuff').each(function workOnStuff() { ... });
معمولاً مشخص نیست که جاوا اسکریپت از عبارات نامگذاری تابع پشتیبانی می کند. انجام این کار باعث می شود که آنها کاملاً در پروفایلر ظاهر شوند. این راه حل یک مشکل دارد: عبارت نامگذاری شده در واقع نام تابع را در محدوده واژگانی فعلی قرار می دهد. این ممکن است نمادهای دیگر را به هم بزند، بنابراین مراقب باشید.
پروفایل توابع طولانی
تصور کنید یک عملکرد طولانی دارید و مشکوک هستید که بخش کوچکی از آن ممکن است دلیل مشکلات عملکرد شما باشد. دو راه برای فهمیدن مشکل در کدام قسمت وجود دارد:
- روش صحیح: کد خود را به گونه ای تغییر دهید که شامل هیچ توابع طولانی نباشد.
- روش شیطانی انجام کارها: عباراتی را در قالب توابع خود فراخوانی نامگذاری شده به کد خود اضافه کنید. اگر کمی مراقب باشید، این امر معنایی را تغییر نمیدهد و باعث میشود بخشهایی از تابع شما بهعنوان توابع مجزا در نمایهگر نشان داده شوند:
js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... }
فراموش نکنید که این توابع اضافی را پس از انجام پروفایل حذف کنید. و یا حتی از آنها به عنوان نقطه شروع برای بازسازی کد خود استفاده کنید.
پروفایل DOM
آخرین ابزارهای توسعه Chrome Web Inspector حاوی "نمای خط زمانی" جدید است که جدول زمانی اقدامات سطح پایین انجام شده توسط مرورگر را نشان می دهد. می توانید از این اطلاعات برای بهینه سازی عملیات DOM خود استفاده کنید. هدف شما باید کاهش تعداد "عملکردهایی" باشد که مرورگر باید هنگام اجرای کد شما انجام دهد.
نمای جدول زمانی می تواند حجم عظیمی از اطلاعات را ایجاد کند. بنابراین باید سعی کنید حداقل موارد آزمایشی را ایجاد کنید که بتوانید مستقل آن را اجرا کنید.
تصویر بالا خروجی نمای تایم لاین را برای یک اسکریپت بسیار ساده نشان می دهد. پنجره سمت چپ عملیات انجام شده توسط مرورگر را به ترتیب مزمن نشان می دهد، در حالی که جدول زمانی در سمت راست زمان واقعی مصرف شده توسط یک عملیات جداگانه را نشان می دهد.
اطلاعات بیشتر در مورد نمای خط زمانی یک ابزار جایگزین برای پروفایل در اینترنت اکسپلورر است DynaTrace Ajax Edition .
استراتژی های پروفایل
جنبه ها را جدا کنید
وقتی میخواهید پروفایل برنامه خود را ایجاد کنید، سعی کنید جنبههایی از عملکرد آن را که ممکن است باعث کندی تا حد ممکن شود، مشخص کنید. سپس سعی کنید یک نمایه اجرا کنید که فقط بخش هایی از کد شما را اجرا کند که مربوط به این جنبه های برنامه شما است. این کار تفسیر دادههای پروفایل را آسانتر میکند زیرا با مسیرهای کدی که به مشکل واقعی شما مرتبط نیستند مخلوط نمیشوند. مثالهای خوب برای جنبههای فردی برنامه شما ممکن است این باشد:
- زمان راه اندازی (پروفایلر را فعال کنید، برنامه را دوباره بارگیری کنید، صبر کنید تا مقداردهی اولیه کامل شود، پروفایلر را متوقف کنید.
- روی یک دکمه و انیمیشن بعدی کلیک کنید (شروع نمایه ساز، روی دکمه کلیک کنید، صبر کنید تا انیمیشن کامل شود، نمایه ساز را متوقف کنید).
پروفایل رابط کاربری گرافیکی
اجرای تنها قسمت سمت راست برنامه شما می تواند در یک برنامه رابط کاربری گرافیکی سخت تر از زمانی باشد که مثلاً ردیاب پرتو موتور سه بعدی خود را بهینه کنید. برای مثال، وقتی میخواهید مواردی را که هنگام کلیک کردن روی دکمهای اتفاق میافتد، نمایه کنید، ممکن است رویدادهای غیر مرتبط با ماوس را در طول مسیر ایجاد کنید که نتایج شما را قطعیتر کند. سعی کن ازش دوری کنی :)
رابط برنامه ای
همچنین یک رابط برنامه نویسی برای فعال کردن دیباگر وجود دارد. این امکان کنترل دقیق زمان شروع و پایان پروفایل را فراهم می کند.
شروع یک پروفایل با:
console.profile()
توقف نمایه سازی با:
console.profileEnd()
تکرارپذیری
وقتی پروفایل انجام می دهید مطمئن شوید که واقعاً می توانید نتایج خود را بازتولید کنید. تنها در این صورت میتوانید بگویید که آیا بهینهسازیهای شما واقعاً چیزها را بهبود بخشیده است یا خیر. همچنین پروفایل سطح عملکرد در زمینه کل رایانه شما انجام می شود. علم دقیقی نیست. اجرای نمایههای فردی ممکن است تحت تأثیر بسیاری از چیزهای دیگر که در رایانه شما اتفاق میافتد باشد:
- یک تایمر نامرتبط در برنامه خودتان که در حالی که چیز دیگری را اندازه میگیرید، فعال میشود.
- زباله جمع کن کارش را می کند.
- برگه دیگری در مرورگر شما که کار سختی را در همان رشته عملیاتی انجام می دهد.
- برنامه دیگری در رایانه شما که از CPU استفاده می کند، بنابراین برنامه شما را کندتر می کند.
- تغییرات ناگهانی در میدان گرانشی زمین.
همچنین اجرای یک مسیر کد چندین بار در یک جلسه نمایه سازی منطقی است. به این ترتیب تأثیر عوامل فوق را کاهش می دهید و قطعات کند ممکن است حتی واضح تر ظاهر شوند.
اندازه گیری، بهبود، اندازه گیری
وقتی نقطه کندی را در برنامه خود شناسایی کردید، سعی کنید به راه هایی برای بهبود رفتار اجرا فکر کنید. بعد از اینکه کد خود را تغییر دادید، دوباره نمایه کنید. اگر از نتیجه راضی هستید، ادامه دهید، اگر بهبودی نمی بینید، احتمالاً باید تغییر خود را به عقب برگردانید و آن را رها نکنید "زیرا نمی تواند صدمه بزند".
استراتژی های بهینه سازی
تعامل DOM را به حداقل برسانید
یک موضوع رایج برای بهبود سرعت برنامههای کلاینت وب، به حداقل رساندن تعامل DOM است. در حالی که سرعت موتورهای جاوا اسکریپت با یک مرتبه افزایش یافته است، دسترسی به DOM با همان سرعت سریعتر نشده است. این نیز به دلایل بسیار عملی است که هرگز اتفاق نخواهد افتاد (چیزهایی مانند چیدمان و ترسیم چیزها روی صفحه فقط زمان می برد).
گره های DOM کش
هر زمان که یک گره یا لیستی از گره ها را از DOM بازیابی می کنید، سعی کنید به این فکر کنید که آیا ممکن است بتوانید آنها را در محاسبات بعدی (یا حتی تکرار حلقه بعدی) دوباره استفاده کنید. تا زمانی که گرهها را در ناحیه مربوطه اضافه یا حذف نکنید، اغلب چنین است.
قبل از:
function getElements() {
return $('.my-class');
}
بعد از:
var cachedElements;
function getElements() {
if (cachedElements) {
return cachedElements;
}
cachedElements = $('.my-class');
return cachedElements;
}
مقادیر ویژگی کش
به همان روشی که می توانید گره های DOM را کش کنید، می توانید مقادیر ویژگی ها را نیز کش کنید. تصور کنید که در حال متحرک سازی یک ویژگی از سبک یک گره هستید. اگر میدانید که شما (مانند آن قسمت از کد) تنها کسی هستید که آن ویژگی را لمس میکنید، میتوانید آخرین مقدار را در هر تکرار ذخیره کنید تا مجبور نباشید آن را به طور مکرر بخوانید.
قبل از:
setInterval(function() {
var ele = $('#element');
var left = parseInt(ele.css('left'), 10);
ele.css('left', (left + 5) + 'px');
}, 1000 / 30);
بعد از: js var ele = $('#element'); var left = parseInt(ele.css('left'), 10); setInterval(function() { left += 5; ele.css('left', left + 'px'); }, 1000 / 30);
دستکاری DOM را از حلقه ها خارج کنید
حلقه ها اغلب نقاط داغ برای بهینه سازی هستند. سعی کنید راه هایی را برای جدا کردن اعداد واقعی از کار با DOM بیاندیشید. اغلب می توان یک محاسبه را انجام داد و پس از انجام آن، همه نتایج را یکجا اعمال کرد.
قبل از:
document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
var val = doSomething(array[i]);
document.getElementById('target').innerHTML += val;
}
بعد از:
var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
var val = doSomething(array[i]);
stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');
دوباره ترسیم و دوباره جریان می یابد
همانطور که قبلا بحث شد دسترسی به DOM نسبتا کند است. زمانی که کد شما مقداری را می خواند که باید دوباره محاسبه شود، بسیار کند می شود زیرا کد شما اخیراً چیزی مربوط به DOM را تغییر داده است. بنابراین، باید از اختلاط دسترسی خواندن و نوشتن به DOM اجتناب شود. در حالت ایده آل کد شما باید همیشه در دو مرحله گروه بندی شود:
- فاز 1: مقادیر DOM لازم برای کد خود را بخوانید
- فاز 2: DOM را اصلاح کنید
سعی کنید الگوهایی مانند:
- فاز 1: خواندن مقادیر DOM
- فاز 2: DOM را اصلاح کنید
- فاز 3: بیشتر بخوانید
- فاز 4: DOM را در جای دیگری تغییر دهید.
قبل از:
function paintSlow() {
var left1 = $('#thing1').css('left');
$('#otherThing1').css('left', left);
var left2 = $('#thing2').css('left');
$('#otherThing2').css('left', left);
}
بعد از:
function paintFast() {
var left1 = $('#thing1').css('left');
var left2 = $('#thing2').css('left');
$('#otherThing1').css('left', left);
$('#otherThing2').css('left', left);
}
این توصیه باید برای اقداماتی که در یک زمینه اجرای جاوا اسکریپت اتفاق می افتد در نظر گرفته شود. (به عنوان مثال در یک کنترل کننده رویداد، در یک کنترل کننده بازه زمانی یا هنگام رسیدگی به یک پاسخ آژاکس.)
اجرای تابع paintSlow()
از بالا این تصویر را ایجاد می کند:
با جابجایی به اجرای سریعتر این تصویر به دست می آید:
این تصاویر نشان می دهد که مرتب کردن مجدد نحوه دسترسی کد شما به DOM می تواند عملکرد رندر را تا حد زیادی افزایش دهد. در این مورد، کد اصلی باید استایلها را دوباره محاسبه کند و صفحه را دو بار طرحبندی کند تا نتیجه یکسانی ایجاد شود. بهینه سازی مشابهی را می توان اساساً برای همه کدهای "دنیای واقعی" اعمال کرد و نتایج واقعاً چشمگیری را به همراه داشت.
بیشتر بخوانید: رندر: repaint، reflow/relayout، restyle توسط Stoyan Stefanov
ترسیم مجدد و حلقه رویداد
اجرای جاوا اسکریپت در مرورگر از مدل "حلقه رویداد" پیروی می کند. به طور پیش فرض مرورگر در حالت "بیکار" است. این حالت می تواند توسط رویدادهایی از تعاملات کاربر یا مواردی مانند تایمرهای جاوا اسکریپت یا تماس های Ajax قطع شود. هر زمان که یک قطعه از جاوا اسکریپت در چنین نقطه وقفه ای اجرا شود، مرورگر معمولاً منتظر می ماند تا آن را به پایان برساند تا زمانی که صفحه را دوباره رنگ کند (ممکن است استثناهایی برای جاوا اسکریپت های طولانی در حال اجرا یا در مواردی مانند جعبه های هشدار که به طور موثر اجرای جاوا اسکریپت را مختل می کنند وجود داشته باشد. ).
عواقب
- اگر اجرای چرخه های انیمیشن جاوا اسکریپت شما بیش از 1/30 ثانیه طول بکشد، نمی توانید انیمیشن های صاف ایجاد کنید زیرا مرورگر در طول اجرای JS دوباره رنگ آمیزی نمی کند. هنگامی که انتظار دارید رویدادهای کاربر را نیز مدیریت کنید، باید بسیار سریعتر باشید.
- گاهی اوقات تأخیر برخی از اقدامات جاوا اسکریپت تا کمی بعد مفید است. به عنوان مثال
setTimeout(function() { ... }, 0)
این به طور موثر به مرورگر میگوید که به محض اینکه حلقه رویداد دوباره بیحرکت میشود، پاسخ تماس را اجرا کند (در عمل برخی از مرورگرها حداقل 10 میلیثانیه صبر خواهند کرد). باید توجه داشته باشید که با این کار دو چرخه اجرای جاوا اسکریپت ایجاد می شود که در زمان بسیار نزدیک به هم هستند. هر دو ممکن است باعث رنگ آمیزی مجدد صفحه شوند که ممکن است زمان کلی صرف شده برای نقاشی را دو برابر کند. اینکه آیا این واقعاً باعث دو رنگ می شود یا خیر، بستگی به اکتشافی در مرورگر دارد.
نسخه معمولی:
function paintFast() {
var height1 = $('#thing1').css('height');
var height2 = $('#thing2').css('height');
$('#otherThing1').css('height', '20px');
$('#otherThing2').css('height', '20px');
}
اجازه دهید کمی تاخیر اضافه کنیم:
function paintALittleLater() {
var height1 = $('#thing1').css('height');
var height2 = $('#thing2').css('height');
$('#otherThing1').css('height', '20px');
setTimeout(function() {
$('#otherThing2').css('height', '20px');
}, 10)
}
نسخه تاخیری نشان میدهد که مرورگر دو بار نقاشی میکند، اگرچه دو تغییر در صفحه فقط 1/100 ثانیه است.
Lazy Initialization
کاربران برنامه های وب را می خواهند که سریع بارگذاری شوند و احساس پاسخگویی داشته باشند. با این حال، کاربران بسته به عملکردی که انجام میدهند، آستانههای متفاوتی برای آهسته بودن آنها دارند. به عنوان مثال، یک برنامه هرگز نباید محاسبات زیادی را روی یک رویداد ماوس انجام دهد زیرا ممکن است در حالی که کاربر به حرکت ماوس خود ادامه می دهد، تجربه کاربری بدی ایجاد کند. با این حال، کاربران عادت دارند پس از کلیک بر روی یک دکمه، کمی تاخیر را بپذیرند.
بنابراین ممکن است منطقی باشد که کد مقداردهی اولیه خود را منتقل کنید تا تا حد امکان دیر اجرا شود (مثلا زمانی که کاربر روی دکمه ای کلیک می کند که یک جزء خاص از برنامه شما را فعال می کند).
قبل: js var things = $('.ele > .other * div.className'); $('#button').click(function() { things.show() });
بعد از: js $('#button').click(function() { $('.ele > .other * div.className').show() });
هیئت رویداد
انتشار کنترلکنندههای رویداد در یک صفحه ممکن است زمان نسبتاً زیادی طول بکشد و همچنین میتواند زمانی که عناصر به صورت پویا جایگزین شوند خستهکننده باشد که پس از آن مستلزم اتصال مجدد کنترلکنندههای رویداد به عناصر جدید است.
راه حل در این مورد استفاده از تکنیکی به نام نمایندگی رویداد است. بهجای پیوستن کنترلکنندههای رویداد جداگانه به عناصر، ماهیت حبابدار بسیاری از رویدادهای مرورگر با پیوست کردن کنترلکننده رویداد به یک گره والد و بررسی گره هدف رویداد برای دیدن اینکه آیا رویداد مورد علاقه است، استفاده میشود.
در jQuery این را می توان به راحتی به صورت زیر بیان کرد:
$('#parentNode').delegate('.button', 'click', function() { ... });
چه زمانی از نمایندگی رویداد استفاده نکنید
گاهی اوقات برعکس میتواند صادق باشد: شما از نمایندگی رویداد استفاده میکنید و مشکل عملکردی دارید. اساساً تفویض رویداد زمان اولیه سازی با پیچیدگی ثابت را امکان پذیر می کند. با این حال، بهای بررسی اینکه آیا یک رویداد مورد علاقه است باید برای هر فراخوانی از آن رویداد پرداخت شود. این ممکن است گران باشد، مخصوصاً برای رویدادهایی که اغلب رخ می دهند مانند "Moeover" یا حتی "Mouve".
مشکلات و راه حل های معمولی
کارهایی که در $(document).ready
انجام می دهم زمان زیادی می برد
توصیه شخصی مالت: هرگز کاری را در $(document).ready
انجام ندهید. سعی کنید سند خود را به شکل نهایی تحویل دهید. خوب، شما مجاز به ثبت شنوندگان رویداد هستید، اما فقط با استفاده از id-selector و/یا استفاده از تفویض رویداد. برای رویدادهای گران قیمت مانند "Moemove"، ثبت نام را تا زمانی که مورد نیاز است به تاخیر بیندازید (رویداد ماوس روی عنصر مربوطه).
و اگر واقعاً نیاز به انجام کارهایی دارید، مانند درخواست Ajax برای دریافت اطلاعات واقعی، سپس یک انیمیشن زیبا نشان دهید. اگر یک GIF متحرک یا موارد مشابه باشد، ممکن است بخواهید انیمیشن را به عنوان URI داده اضافه کنید.
از آنجایی که یک فیلم فلش را به صفحه اضافه کردم، همه چیز واقعا کند است
افزودن فلش به یک صفحه همیشه رندر را کمی کند می کند زیرا طرح نهایی پنجره باید بین مرورگر و افزونه Flash "مذاکره" شود. هنگامی که نمی توانید به طور کامل از قرار دادن فلش در صفحات خود اجتناب کنید، مطمئن شوید که پارامتر Flash "wmode" را روی مقدار "window" (که پیش فرض است) تنظیم کرده اید. این قابلیت ترکیب عناصر HTML و Flash را غیرفعال میکند (شما نمیتوانید عنصر HTML را که بالای فیلم Flash قرار دارد ببینید و فیلم فلش شما شفاف نباشد). این ممکن است یک ناراحتی باشد اما عملکرد شما را به طور چشمگیری بهبود می بخشد. برای مثال روشی را که youtube.com با دقت از قرار دادن لایهها در بالای پخشکننده اصلی فیلم اجتناب میکند، بررسی کنید.
من چیزها را در localStorage ذخیره می کنم، اکنون برنامه من دچار لکنت می شود
نوشتن در localStorage یک عملیات همزمان است که شامل چرخاندن هارد دیسک شما می شود. شما هرگز نمی خواهید هنگام انجام انیمیشن ها عملیات همزمان "طولانی" را انجام دهید. دسترسی به LocalStorage را به نقطه ای از کد خود منتقل کنید که مطمئن هستید کاربر بیکار است و هیچ انیمیشنی در حال انجام نیست.
نمایه سازی نشان می دهد که انتخابگر جی کوئری واقعا کند است
ابتدا می خواهید مطمئن شوید که انتخابگر شما می تواند از طریق document.querySelectorAll اجرا شود. می توانید آن را در کنسول جاوا اسکریپت تست کنید. اگر استثنا وجود دارد، انتخابگر خود را بازنویسی کنید تا از هیچ پسوند خاصی از چارچوب جاوا اسکریپت خود استفاده نکنید. این کار انتخابگر شما را در مرورگرهای مدرن با مرتبه بزرگی سرعت می بخشد.
اگر این کمک نمی کند یا اگر می خواهید در مرورگرهای مدرن سریع باشید، این دستورالعمل ها را دنبال کنید:
- تا حد امکان در سمت راست انتخابگر خود مشخص باشید.
- از نام برچسبی استفاده کنید که اغلب از آن به عنوان سمت راست ترین قسمت انتخابگر استفاده نمی کنید.
- اگر هیچ کمکی نکرد، به بازنویسی چیزها فکر کنید تا بتوانید از یک id-selector استفاده کنید
تمام این دستکاری های DOM زمان زیادی می برد
دستهای از درجها، حذفها و بهروزرسانیهای گره DOM میتوانند واقعاً کند باشند. به طور کلی می توان با ایجاد یک رشته بزرگ از html و استفاده از domNode.innerHTML = newHTML
برای جایگزینی محتوای قدیمی بهینه سازی کرد. توجه داشته باشید که این ممکن است برای نگهداری بسیار بد باشد و ممکن است پیوندهای حافظه را در IE ایجاد کند، پس مراقب باشید.
یکی دیگر از مشکلات رایج این است که کد اولیه شما ممکن است مقدار زیادی HTML ایجاد کند. به عنوان مثال یک پلاگین jQuery که یک جعبه انتخاب را به مجموعهای از div تبدیل میکند، زیرا این همان چیزی است که افراد طراحی بدون اطلاع از بهترین شیوههای UX میخواستند. اگر واقعاً می خواهید صفحه شما سریع باشد، هرگز این کار را نکنید. در عوض تمام نشانهگذاریها را از سمت سرور به شکل نهایی تحویل دهید. این دوباره مشکلات زیادی دارد، بنابراین خوب فکر کنید که آیا سرعت ارزش آن را دارد یا خیر.
ابزار
- JSPerf - نمونه های کوچک جاوا اسکریپت را معیار قرار دهید
- Firebug - برای پروفایل در فایرفاکس
- ابزارهای توسعه دهنده Google Chrome (در دسترس به عنوان WebInspector در سافاری)
- DOM Monster - برای بهینه سازی عملکرد DOM
- DynaTrace Ajax Edition - برای پروفایل و بهینه سازی رنگ در اینترنت اکسپلورر