Giriş
HTML5, web uygulamalarının görsel görünümünü iyileştirmek için bize mükemmel araçlar sunar. Bu durum özellikle animasyonlar için geçerlidir. Ancak bu yeni güçle birlikte yeni zorluklar da gelir. Aslında bu zorluklar o kadar da yeni değil ve bazen Flash programcısı olan, samimi iş arkadaşınıza geçmişte benzer sorunları nasıl çözdüğünü sormanız yararlı olabilir.
Animasyonda çalışırken kullanıcıların bu animasyonların akıcı olduğunu algılaması çok önemlidir. Animasyonlarda akıcılığın, saniyedeki kare sayısını herhangi bir bilişsel eşiğin üzerine çıkararak elde edilemeyeceğini anlamamız gerekir. Maalesef beynimiz bundan daha akıllı. Saniyede 30 kare (fps) gerçek animasyon, ortasında birkaç kare atlanmış 60 fps'den çok daha iyidir. Kullanıcılar pürüzlülükten nefret eder.
Bu makalede, kendi uygulamanızın deneyimini iyileştirmek için kullanabileceğiniz araç ve teknikler sunulmaya çalışılmaktadır.
Strateji
HTML5 ile muhteşem ve çarpıcı görsel uygulamalar oluşturmaktan vazgeçmenizi kesinlikle istemiyoruz.
Ardından, performansın biraz daha iyi olabileceğini fark ettiğinizde buraya geri dönün ve uygulamanızın öğelerini nasıl iyileştirebileceğinizi okuyun. Elbette bazı şeyleri baştan doğru yapmak faydalı olabilir ancak bu, üretken olmanızı engellememelidir.
HTML5 ile görsel doğruluk++
Donanım Hızlandırma
Donanım hızlandırma, tarayıcıdaki genel oluşturma performansı için önemli bir aşamadır. Genel şema, ana CPU tarafından hesaplanabilecek görevleri bilgisayarınızın grafik adaptörünün grafik işlem birimine (GPU) aktarmaktır. Bu, performansta büyük kazanımlar sağlayabilir ve mobil cihazlardaki kaynak tüketimini de azaltabilir.
Belgenizin bu yönleri GPU tarafından hızlandırılabilir
- Genel düzen oluşturma
- CSS3 geçişleri
- CSS3 3D dönüştürme işlemleri
- Kanvas Çizimi
- WebGL 3D Çizim
Tuval ve WebGL hızlandırması, özel amaçlı özellikler olup belirli uygulamanız için geçerli olmayabilir. Ancak ilk üç özellik, hemen hemen her uygulamanın daha hızlı olmasına yardımcı olabilir.
Neler hızlandırılabilir?
GPU hızlandırma, iyi tanımlanmış ve belirli görevleri özel amaçlı donanıma aktararak çalışır. Genel şema, belgenizin sayfanızı hızlandıran yönlere göre değişmeyen birden fazla "katmana" ayrılmasıdır. Bu katmanlar, geleneksel oluşturma ardışık düzeni kullanılarak oluşturulur. Ardından GPU, katmanları tek bir sayfada birleştirmek için kullanılır. Bu işlem sırasında anında hızlandırılabilen "efektler" uygulanır. Olası bir sonuç, ekranda animasyonlu bir nesnenin animasyon sırasında sayfanın tek bir "yeniden düzenlenmesini" gerektirmemesidir.
Buradan çıkarmanız gereken sonuç, oluşturma motorunun GPU hızlandırma özelliğini ne zaman uygulayabileceğini belirlemesini kolaylaştırmanız gerektiğidir. Aşağıdaki örneği inceleyin:
Bu yöntem işe yarar ancak tarayıcı, bir insan tarafından sorunsuz animasyon olarak algılanacağı varsayılan bir işlem gerçekleştirdiğinizi bilmez. Bunun yerine CSS3 geçişlerini kullanarak aynı görsel görünüme ulaştığınızda neler olacağını düşünün:
Tarayıcının bu animasyonu nasıl uyguladığı geliştiriciden tamamen gizlenir. Bu da tarayıcının, tanımlanan hedefe ulaşmak için GPU hızlandırma gibi hileler uygulayabileceği anlamına gelir.
Chrome'da GPU hızlandırmayla ilgili hataları ayıklamaya yardımcı olan iki yararlı komut satırı işareti vardır:
--show-composited-layer-borders
, GPU düzeyinde manipüle edilen öğelerin etrafında kırmızı bir sınır gösterir. Değişikliklerinizin GPU katmanında gerçekleştiğini onaylamak için kullanışlıdır.--show-paint-rects
GPU dışındaki tüm değişiklikler boyanır ve bu, yeniden boyanan tüm alanların etrafına açık bir kenar çizgisi atar. Tarayıcıda boya alanlarını optimize etme işlemini görebilirsiniz.
Safari'de burada açıklanan benzer çalışma zamanı işaretleri vardır.
CSS3 Geçişleri
CSS geçişleri, stil animasyonunu herkes için basitleştirir ancak aynı zamanda akıllı bir performans özelliğidir. CSS geçişi tarayıcı tarafından yönetildiğinden, animasyonunun doğruluğu büyük ölçüde iyileştirilebilir ve çoğu durumda donanım hızlandırması uygulanabilir. Şu anda WebKit (Chrome, Safari, iOS) donanım hızlandırmalı CSS dönüşümlerine sahiptir ancak bu özellik diğer tarayıcılara ve platformlara hızla eklenmektedir.
Bu bilgileri güçlü kombinasyonlar halinde komut dosyası haline getirmek için transitionEnd
etkinliklerini kullanabilirsiniz. Ancak şu anda desteklenen tüm geçiş sonu etkinliklerini yakalamak için webkitTransitionEnd transitionend oTransitionEnd
'ı izlemeniz gerekir.
Birçok kitaplık artık geçişler varsa geçişlerden yararlanan ve aksi takdirde standart DOM stili animasyona geri dönen animasyon API'leri kullanıma sunmuştur. scripty2, YUI transition, jQuery animate enhanced.
CSS3 Translate
Daha önce bir öğenin sayfadaki x/y konumunu animasyonlu hale getirdiğinizden eminim. Satır içi stilin sol ve üst özelliklerini değiştirmiş olabilirsiniz. 2D dönüştürmelerde bu davranışı kopyalamak için translate()
işlevini kullanabiliriz.
Mümkün olan en iyi deneyimi sunmak için bunu DOM animasyonuyla birlikte kullanabiliriz.
<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>
CSS 2D Dönüşümler ve CSS Geçişleri için özellik testi yapmak üzere Modernizr'i kullanırız. Bu durumda, konumu değiştirmek için translate işlevini kullanırız. Bu animasyon geçiş kullanılarak oluşturulduysa tarayıcının donanım hızlandırması yapması olasıdır. Tarayıcıyı doğru yönde bir kez daha itmek için yukarıdaki "sihirli CSS mermisini" kullanacağız.
Tarayıcımız daha az özellikliyse öğemizi taşımak için jQuery'ye geri döneriz. Tüm bu işlemi otomatik hale getirmek için Louis-Remi Babe tarafından geliştirilen jQuery Transform polyfill eklentisini kullanabilirsiniz.
window.requestAnimationFrame
requestAnimationFrame
, Mozilla tarafından kullanıma sunulmuş ve WebKit tarafından DOM/CSS tabanlı veya <canvas>
ya da WebGL'de animasyon çalıştırmak için yerel bir API sağlamak amacıyla geliştirilmiştir. Tarayıcı, eşzamanlı animasyonlar için tek bir yeniden akış ve yeniden boyama döngüsü oluşturarak animasyon kalitesini artırabilir. Örneğin, CSS geçişleri veya SVG SMIL ile senkronize edilen JS tabanlı animasyonlar. Ayrıca, animasyon döngüsünü görünmeyen bir sekmede çalıştırırsanız tarayıcı bunu çalıştırmaya devam etmez. Bu da CPU, GPU ve bellek kullanımının azalmasına, dolayısıyla pil ömrünün çok daha uzun olmasına neden olur.
requestAnimationFrame
işlevinin nasıl ve neden kullanılacağı hakkında daha fazla bilgi için Paul Irish'ın Akıllı animasyon için requestAnimationFrame makalesini inceleyin.
Profil oluşturma
Uygulamanızın hızının iyileştirilebileceğini fark ettiğinizde, optimizasyonların en büyük faydayı nerede sağlayabileceğini öğrenmek için profil oluşturma işlemine başlamanız gerekir. Optimizasyonlar genellikle kaynak kodunuzun sürdürülebilirliği üzerinde olumsuz bir etki yapar. Bu nedenle, yalnızca gerektiğinde uygulanmalıdır. Profil oluşturma, performansı artırıldığında kodunuzun hangi bölümlerinin en büyük faydayı sağlayacağını gösterir.
JavaScript Profilleme
JavaScript profilleyiciler, her bir işlevin başlangıcından sonuna kadar çalıştırılmasının ne kadar sürdüğünü ölçerek uygulamanızın JavaScript işlevi düzeyindeki performansına genel bir bakış sunar.
Bir işlevin toplam yürütme süresi, işlevin baştan sona yürütülmesi için gereken toplam süredir. Net yürütme süresi, işlevden çağrılan işlevlerin yürütülmesi için harcanan sürenin çıkarıldığı brüt yürütme süresidir.
Bazı işlevler diğerlerinden daha sık çağrılır. Profilleyiciler genellikle tüm çağrıların çalışmasının yanı sıra ortalama, minimum ve maksimum yürütme süresini de gösterir.
Daha fazla bilgi için profil oluşturma hakkındaki Chrome Geliştirici Araçları dokümanlarına göz atın.
DOM
JavaScript'in performansı, uygulamanızın ne kadar akıcı ve duyarlı olacağına büyük ölçüde etki eder. JavaScript profilleyiciler, JavaScript'inizin yürütme süresini ölçerken dolaylı olarak DOM işlemlerinin yapılmasına harcanan süreyi de ölçer. Bu DOM işlemleri genellikle performans sorunlarınızın merkezinde yer alır.
function drawArray(array) {
for(var i = 0; i < array.length; i++) {
document.getElementById('test').innerHTML += array[i]; // No good :(
}
}
Örneğin, yukarıdaki kodda gerçek JavaScript'in yürütülmesi için neredeyse hiç zaman harcanmaz. drawArray işlevi, DOM ile çok verimsiz bir şekilde etkileşimde bulunduğundan profillerinizde görünme olasılığı yüksektir.
İpuçları ve Püf Noktaları
Anonim İşlevler
Anonim işlevlerin profil oluşturması kolay değildir çünkü bu işlevler doğası gereği profil oluşturucuda gösterilebilecek bir ada sahip değildir. Bu sorunun üstesinden gelmenin iki yolu vardır:
$('.stuff').each(function() { ... });
Yeniden yazmak için:
$('.stuff').each(function workOnStuff() { ... });
JavaScript'in işlev ifadelerini adlandırmayı desteklediği genellikle bilinmez. Bu işlem, bu öğelerin profilleyicide mükemmel şekilde gösterilmesini sağlar. Bu çözümün bir sorunu vardır: Adlandırılmış ifade, işlev adını mevcut söz dizimi kapsamına yerleştirir. Bu, diğer sembolleri bozabilir. Bu nedenle dikkatli olun.
Uzun işlevlerin profilini oluşturma
Uzun bir işleviniz olduğunu ve performans sorunlarınızın nedeninin işlevin küçük bir kısmı olabileceğinden şüphelendiğinizi varsayalım. Sorunun hangi bölümde olduğunu öğrenmenin iki yolu vardır:
- Doğru yöntem: Kodunuzu uzun işlevler içermeyecek şekilde yeniden yapılandırın.
- İşleri halletmenin kötü yöntemi: Kodunuza, kendini çağıran adlandırılmış işlevler biçiminde ifadeler ekleyin. Biraz dikkatli olursanız bu işlem semantiği değiştirmez ve işlevinizin bölümlerini profilleyicide ayrı işlevler olarak gösterir:
js function myLongFunction() { ... (function doAPartOfTheWork() { ... })(); ... }
Profil oluşturma işlemi tamamlandıktan sonra bu ek işlevleri kaldırmayı veya hatta kodunuzu yeniden yapılandırmak için başlangıç noktası olarak kullanmayı unutmayın.
DOM Profilleme
En son Chrome Web İnspector geliştirme araçları, tarayıcı tarafından gerçekleştirilen düşük düzeydeki işlemlerin zaman çizelgesini gösteren yeni "Zaman Çizelgesi Görünümü"nü içerir. Bu bilgileri DOM işlemlerinizi optimize etmek için kullanabilirsiniz. Kodunuz yürütülürken tarayıcının gerçekleştirmesi gereken "işlem" sayısını azaltmayı hedeflemeniz gerekir.
Zaman çizelgesi görünümü çok fazla bilgi oluşturabilir. Bu nedenle, bağımsız olarak yürütebileceğiniz minimum test örnekleri oluşturmaya çalışmalısınız.
Yukarıdaki resimde, çok basit bir komut dosyası için zaman çizelgesi görünümünün çıktısı gösterilmektedir. Sol bölmede, tarayıcı tarafından gerçekleştirilen işlemler kronolojik sırayla gösterilirken sağ bölmede, tek bir işlemin tükettiği gerçek süre gösterilir.
Zaman çizelgesi görünümü hakkında daha fazla bilgi Internet Explorer'da profil oluşturmak için alternatif bir araç DynaTrace Ajax Edition'dır.
Profil Oluşturma Stratejileri
Öğeleri öne çıkarma
Uygulamanızın profilini çıkarmak istediğinizde, işlevselliğinin yavaşlığı tetikleyebilecek yönlerini mümkün olduğunca ayrıntılı bir şekilde belirlemeye çalışın. Ardından, yalnızca kodunuzun uygulamanızın bu yönleriyle alakalı bölümlerini yürüten bir profil çalıştırmayı deneyin. Bu sayede, gerçek sorununuzla ilgili olmayan kod yollarıyla karıştırılmadığından profil oluşturma verilerinin yorumlanması kolaylaşır. Başvurunuzun farklı yönlerine örnek olarak şunlar verilebilir:
- Başlatma süresi (profil oluşturucuyu etkinleştirin, uygulamayı yeniden yükleyin, ilk kullanıma hazırlama işleminin tamamlanmasını bekleyin, profil oluşturucuyu durdurun.
- Bir düğmeyi ve ardından animasyonu tıklayın (profil oluşturucuyu başlatın, düğmeyi tıklayın, animasyon tamamlanana kadar bekleyin, profil oluşturucuyu durdurun).
GUI Profil Oluşturma
Uygulamanızın yalnızca doğru bölümünü yürütmek, GUI programında 3D motorunuzun ışın izleyicisini optimize ettiğinizden daha zor olabilir. Örneğin, bir düğmeyi tıkladığınızda gerçekleşen işlemleri profillemek istediğinizde, bu süreçte alakasız fareyle üzerine gelme etkinlikleri tetikleyebilirsiniz. Bu da sonuçlarınızın daha az kesin olmasını sağlar. Bunu önlemeye çalışın :)
Programatik Arayüz
Hata ayıklayıcıyı etkinleştirmek için programatik bir arayüz de vardır. Bu sayede, profillemenin ne zaman başlayıp ne zaman sona ereceği konusunda hassas kontrol sahibi olabilirsiniz.
Aşağıdakilerle profil oluşturmaya başlayın:
console.profile()
Aşağıdakilerle profil oluşturmayı durdurun:
console.profileEnd()
Tekrarlanabilirlik
Profil oluşturma işlemi yaparken sonuçlarınızı gerçekten yeniden oluşturabileceğinizden emin olun. Yalnızca bu durumda, optimizasyonlarınızın gerçekten bir iyileşme sağlayıp sağlamadığını anlayabilirsiniz. Ayrıca işlev düzeyinde profil oluşturma işlemi, bilgisayarınızın tamamı bağlamında gerçekleştirilir. Bu kesin bir kural değildir. Tek tek profil çalıştırma işlemleri, bilgisayarınızda gerçekleşen diğer birçok şeyden etkilenebilir:
- Kendi uygulamanızda, başka bir şeyi ölçerken etkinleşen alakasız bir zamanlayıcı.
- Çöp toplayıcı işini yapıyor.
- Tarayıcınızdaki başka bir sekme, aynı işletim iş parçacığında yoğun şekilde çalışıyor.
- Bilgisayarınızdaki başka bir program CPU'yu kullanarak uygulamanızı yavaşlatıyor olabilir.
- Dünyanın yerçekimi alanındaki ani değişiklikler.
Aynı kod yolunu tek bir profil oluşturma oturumunda birden çok kez yürütmek de mantıklıdır. Böylece yukarıdaki faktörlerin etkisini azaltırsınız ve yavaş bölümler daha da belirgin hale gelebilir.
Ölçün, iyileştirin, ölçün
Programınızda yavaş bir nokta belirlediğinizde yürütme davranışını iyileştirmenin yollarını düşünmeye çalışın. Kodunuzu değiştirdikten sonra tekrar profilinizi değiştirin. Sonuçtan memnunsanız devam edin. İyileşme görmüyorsanız muhtemelen değişikliğinizi geri almalı ve "zarar vermeyeceği için" bu şekilde bırakmamalısınız.
Optimizasyon Stratejileri
DOM etkileşimini en aza indirme
Web istemci uygulamalarının hızını iyileştirmek için yaygın olarak kullanılan bir yöntem, DOM etkileşimini en aza indirmektir. JavaScript motorlarının hızı büyük oranda artmış olsa da DOM'a erişim aynı oranda hızlanmamıştır. Bu, çok pratik nedenlerden dolayı da hiçbir zaman gerçekleşmeyecektir (ekran üzerinde düzen oluşturma ve çizim yapma gibi işlemler zaman alır).
DOM Düğümlerini Önbelleğe Alma
DOM'dan bir düğüm veya düğüm listesi aldığınızda bunları daha sonraki bir hesaplamada (veya hatta sonraki döngü iterasyonunda) yeniden kullanabilmenizin mümkün olup olmadığını düşünmeye çalışın. İlgili alanda düğüm eklemediğiniz veya silmediğiniz sürece genellikle bu durumla karşılaşırsınız.
Önce:
function getElements() {
return $('.my-class');
}
Sonra:
var cachedElements;
function getElements() {
if (cachedElements) {
return cachedElements;
}
cachedElements = $('.my-class');
return cachedElements;
}
Özellik Değerlerini Önbelleğe Alma
DOM düğümlerini önbelleğe alabildiğiniz gibi özelliklerin değerlerini de önbelleğe alabilirsiniz. Bir düğümün stil özelliğini animasyonlu hale getirdiğinizi düşünün. Bu özelliğe hiç dokunmayacak tek kişinin siz olduğunuzu (kodun bu kısmında olduğu gibi) biliyorsanız her iterasyonda son değeri önbelleğe alabilirsiniz. Böylece, tekrar tekrar okumak zorunda kalmazsınız.
Önce:
setInterval(function() {
var ele = $('#element');
var left = parseInt(ele.css('left'), 10);
ele.css('left', (left + 5) + 'px');
}, 1000 / 30);
Sonra:
js
var ele = $('#element');
var left = parseInt(ele.css('left'), 10);
setInterval(function() {
left += 5;
ele.css('left', left + 'px');
}, 1000 / 30);
DOM Manipülasyonunu Döngülerden Dışarı Taşıma
Döngüler genellikle optimizasyon için önemli noktalardır. Gerçek sayısal işlemlerden DOM ile çalışmayı ayırmanın yollarını düşünmeye çalışın. Genellikle bir hesaplama yaptıktan sonra tüm sonuçları tek seferde uygulamak mümkündür.
Önce:
document.getElementById('target').innerHTML = '';
for(var i = 0; i < array.length; i++) {
var val = doSomething(array[i]);
document.getElementById('target').innerHTML += val;
}
Sonra:
var stringBuilder = [];
for(var i = 0; i < array.length; i++) {
var val = doSomething(array[i]);
stringBuilder.push(val);
}
document.getElementById('target').innerHTML = stringBuilder.join('');
Yeniden çizimler ve yeniden akışlar
Daha önce de belirtildiği gibi DOM'a erişim nispeten yavaştır. Kodunuz DOM'da ilgili bir şeyi yakın zamanda değiştirdiği için yeniden hesaplanması gereken bir değeri okurken çok yavaşlar. Bu nedenle, DOM'a okuma ve yazma erişiminin karıştırılmasından kaçınılmalıdır. İdeal olarak kodunuz her zaman iki aşamada gruplandırılmalıdır:
- 1. Aşama: Kodunuz için gerekli DOM değerlerini okuyun
- 2. Aşama: DOM'u değiştirin
Aşağıdaki gibi bir kalıp programlamamaya çalışın:
- 1. Aşama: DOM değerlerini okuma
- 2. Aşama: DOM'u değiştirin
- 3. Aşama: Daha fazla bilgi edinin
- 4. Aşama: DOM'u başka bir yerde değiştirin.
Önce:
function paintSlow() {
var left1 = $('#thing1').css('left');
$('#otherThing1').css('left', left);
var left2 = $('#thing2').css('left');
$('#otherThing2').css('left', left);
}
Sonra:
function paintFast() {
var left1 = $('#thing1').css('left');
var left2 = $('#thing2').css('left');
$('#otherThing1').css('left', left);
$('#otherThing2').css('left', left);
}
Bu öneri, tek bir JavaScript yürütme bağlamında gerçekleşen işlemler için dikkate alınmalıdır. (ör. bir etkinlik işleyici içinde, bir aralık işleyici içinde veya bir ajax yanıtı işlenirken).
Yukarıdaki paintSlow()
işlevi çalıştırıldığında aşağıdaki resim oluşturulur:
Daha hızlı uygulamaya geçiş yaptığınızda aşağıdaki resim gösterilir:
Bu resimler, kodunuzun DOM'a erişim şeklini yeniden sıralamanın oluşturma performansını büyük ölçüde artırabileceğini gösterir. Bu durumda, orijinal kodun aynı sonucu oluşturmak için stilleri yeniden hesaplaması ve sayfayı iki kez düzenlemiş olması gerekir. Benzer optimizasyonlar, temel olarak tüm "gerçek dünya" kodlarına uygulanabilir ve gerçekten çarpıcı sonuçlar verebilir.
Daha fazla bilgi: Stoyan Stefanov tarafından yazılan Görüntü işleme: yeniden boyama, yeniden akış/yeniden düzen, yeniden stillendirme
Yeniden çizimler ve etkinlik döngüsü
Tarayıcıda JavaScript yürütme, "Etkinlik Döngüsü" modelini izler. Tarayıcı varsayılan olarak "bekleme" durumundadır. Bu durum, kullanıcı etkileşimlerinden kaynaklanan etkinlikler veya JavaScript zamanlayıcıları ya da Ajax geri çağırma işlemleri gibi unsurlar tarafından kesintiye uğratılabilir. Bir JavaScript parçası bu tür bir kesinti noktasında çalıştırıldığında tarayıcı genellikle ekranı yeniden boyamadan önce parçanın tamamlanmasını bekler (Son derece uzun süre çalışan JavaScript'ler veya JavaScript yürütmesini etkili bir şekilde kesintiye uğratan uyarı kutuları gibi durumlarda istisnalar olabilir).
Sonuçlar
- JavaScript animasyon döngülerinizin yürütülmesi 1/30 saniyeden uzun sürerse tarayıcı JS yürütülmesi sırasında yeniden boyanmayacağından sorunsuz animasyonlar oluşturamazsınız. Kullanıcı etkinliklerini de işlemek istiyorsanız çok daha hızlı olmanız gerekir.
- Bazen bazı JavaScript işlemlerini biraz daha sonraya ertelemek yararlı olabilir.
Ör.
setTimeout(function() { ... }, 0)
Bu, tarayıcıya etkinlik döngüsü tekrar boş olduğunda geri çağırma işlevini yürütmesini söyler (bazı tarayıcılar en az 10 ms bekler). Bunun, zaman açısından birbirine çok yakın iki JavaScript yürütme döngüsü oluşturacağını unutmayın. Her ikisi de ekranın yeniden boyanmasını tetikleyebilir. Bu da boyama işleminin toplam süresini ikiye katlayabilir. Bunun gerçekten iki boya tetikleyip tetiklemediği tarayıcıdaki sezgisel kurallara bağlıdır.
Normal sürüm:
function paintFast() {
var height1 = $('#thing1').css('height');
var height2 = $('#thing2').css('height');
$('#otherThing1').css('height', '20px');
$('#otherThing2').css('height', '20px');
}
Biraz gecikme ekleyelim:
function paintALittleLater() {
var height1 = $('#thing1').css('height');
var height2 = $('#thing2').css('height');
$('#otherThing1').css('height', '20px');
setTimeout(function() {
$('#otherThing2').css('height', '20px');
}, 10)
}
Gecikmeli sürümde, sayfadaki iki değişiklik yalnızca 1/100 saniye olmasına rağmen tarayıcının iki kez boyadığı görülüyor.
Geç Başlatma
Kullanıcılar hızlı yüklenen ve duyarlı hissettiren web uygulamaları ister. Ancak kullanıcılar, yaptıkları işleme bağlı olarak yavaş olarak algıladıkları işlemler için farklı eşiklere sahiptir. Örneğin, bir uygulama fareyle üzerine gelme etkinliğinde hiçbir zaman çok fazla hesaplama yapmamalıdır. Aksi takdirde, kullanıcı faresini hareket ettirmeye devam ederken kötü bir kullanıcı deneyimi oluşabilir. Ancak kullanıcılar, bir düğmeyi tıkladıktan sonra biraz gecikme yaşanmasını kabul etmeye alışkındır.
Bu nedenle, başlatma kodunuzu mümkün olduğunca geç bir zamanda (ör. kullanıcı, uygulamanızın belirli bir bileşenini etkinleştiren bir düğmeyi tıkladığında) yürütülecek şekilde taşımanız yararlı olabilir.
Önce:
js
var things = $('.ele > .other * div.className');
$('#button').click(function() { things.show() });
Sonra:
js
$('#button').click(function() { $('.ele > .other * div.className').show() });
Etkinlik Yetkilendirmesi
Etkinlik işleyicileri bir sayfaya dağıtmak nispeten uzun sürebilir ve öğeler dinamik olarak değiştirildikten sonra etkinlik işleyicilerinin yeni öğelere yeniden bağlanması gerektiğinden sıkıcı olabilir.
Bu durumda çözüm, etkinlik yetkilendirmesi adı verilen bir tekniği kullanmaktır. Öğelere tek tek etkinlik işleyicileri eklemek yerine, etkinlik işleyiciyi bir üst öğeye ekleyerek ve etkinliğin ilgi çekici olup olmadığını görmek için etkinliğin hedef öğesini kontrol ederek birçok tarayıcı etkinliğinin kabarcıklanma özelliği kullanılır.
jQuery'de bu kolayca şu şekilde ifade edilebilir:
$('#parentNode').delegate('.button', 'click', function() { ... });
Etkinlik yetkilendirmesi ne zaman kullanılmamalıdır?
Bazen bunun tam tersi de doğru olabilir: Etkinlik yetkilendirmesini kullanıyorsanız ve performans sorunu yaşıyorsanız. Temel olarak etkinlik yetkilendirmesi, sabit karmaşıklıkta ilk başlatma süresine olanak tanır. Ancak bir etkinliğin ilgi çekip çekmediğini kontrol etmenin bedeli, söz konusu etkinliğin her çağrısı için ödenmelidir. Bu, özellikle "fareyle üzerine gelme" veya hatta "fare hareketi" gibi sık gerçekleşen etkinlikler için maliyetli olabilir.
Sık Karşılaşılan Sorunlar ve Çözümleri
$(document).ready
'te yaptığım işlemler çok uzun sürüyor
Malte'nin kişisel tavsiyesi: $(document).ready
'te hiçbir zaman işlem yapmayın. Belgenizi son biçiminde göndermeyi deneyin. Tamam, etkinlik dinleyicileri kaydetmenize izin verilir ancak yalnızca kimlik seçiciyi ve/veya etkinlik yetkilendirmesini kullanarak. "mousemove" gibi pahalı etkinlikler için kaydı, gerekli olana kadar erteleyin (ilgili öğe üzerinde fareyle üzerine gelme etkinliği).
Gerçek verileri almak için Ajax isteği göndermek gibi bir işlem yapmanız gerekiyorsa güzel bir animasyon gösterin. Animasyonlu GIF veya benzeri bir animasyon kullanıyorsanız animasyonu veri URI'si olarak ekleyebilirsiniz.
Sayfaya Flash filmi eklediğimden beri her şey çok yavaş
Bir sayfaya Flash eklendiğinde, pencerenin nihai düzeninin tarayıcı ile Flash eklentisi arasında "pazarlık" edilmesi gerektiğinden oluşturma işlemi her zaman biraz yavaşlar. Sayfalarınıza Flash yerleştirmekten tamamen kaçınamadığınızda "wmode" Flash parametresini "window" değerine (varsayılan değer) ayarladığınızdan emin olun. Bu işlem, HTML ve Flash öğelerini birleştirme özelliğini devre dışı bırakır (Flash filminin üzerinde bulunan bir HTML öğesini göremezsiniz ve Flash filminiz şeffaf olamaz). Bu durum can sıkıcı olabilir ancak performansınızı önemli ölçüde artıracaktır. Örneğin, youtube.com'un ana film oynatıcının üzerine katman yerleştirmekten nasıl dikkatli bir şekilde kaçındığına bakın.
localStorage'a öğe kaydediyorum, şimdi uygulamam takılıyor
localStorage'a yazma işlemi, sabit diskinizin başlatılmasını içeren senkronize bir işlemdir. Animasyon yaparken "uzun süren" eşzamanlı işlemler yapmak istemezsiniz. localStorage erişimini, kodunuzda kullanıcının boşta olduğundan ve animasyon olmadığından emin olduğunuz bir noktaya taşıyın.
Profilleme, bir jQuery seçicinin gerçekten yavaş olduğunu gösteriyor
Öncelikle seçicinizin document.querySelectorAll aracılığıyla çalıştırılabileceğinden emin olmanız gerekir. Bunu JavaScript konsolunda test edebilirsiniz. Bir istisna varsa seçicinizi, JavaScript çerçevenizin özel bir uzantısını kullanmayacak şekilde yeniden yazın. Bu, modern tarayıcılarda seçicinizi önemli ölçüde hızlandırır.
Bu yöntem işe yaramazsa veya modern tarayıcılarda da hızlı olmak istiyorsanız aşağıdaki yönergeleri uygulayın:
- Seçicinizin sağ tarafında mümkün olduğunca ayrıntılı bilgi verin.
- En sağdaki seçici bölümü olarak sık kullanmadığınız bir etiket adı kullanın.
- Hiçbir şey işe yaramazsa kimlik seçici kullanabilmek için kodları yeniden yazmayı deneyin.
Tüm bu DOM manipülasyonları uzun zaman alır
Çok sayıda DOM düğümü ekleme, kaldırma ve güncelleme işlemi gerçekten yavaş olabilir. Bu durum genellikle büyük bir HTML dizesi oluşturarak ve eski içeriği değiştirmek için domNode.innerHTML = newHTML
kullanarak optimize edilebilir. Bunun sürdürülebilirlik açısından çok kötü olabileceğini ve IE'de bellek bağlantıları oluşturabileceğini unutmayın.
Sık karşılaşılan bir diğer sorun da, başlatma kodunuzun çok fazla HTML oluşturmasıdır. Örneğin, tasarım ekibinin kullanıcı deneyimi en iyi uygulamalarına aldırmadan istediği şekilde bir seçim kutusunu bir grup div'e dönüştüren bir jQuery eklentisi. Sayfanızın gerçekten hızlı olmasını istiyorsanız bunu hiçbir zaman yapmayın. Bunun yerine, tüm işaretlemeyi sunucu tarafında nihai biçiminde yayınlayın. Bu yöntemin de birçok sorunu vardır. Bu nedenle, hız avantajının bu dezavantajlara değip değmeyeceğini iyi düşünün.
Araçlar
- JSPerf - Küçük JavaScript snippet'lerinin karşılaştırması
- Firebug - Firefox'ta profil oluşturma için
- Google Chrome Geliştirici Araçları (Safari'de WebInspector olarak kullanılabilir)
- DOM Monster - DOM performansını optimize etmek için
- DynaTrace Ajax Edition - Internet Explorer'da profil oluşturma ve boyama optimizasyonları için