JavaScript'te bir dizi arasında geçiş yapmanın en hızlı yolu nedir?


249

Kitaplardan döngü için böyle yazman gerektiğini öğrendim :

for(var i=0, len=arr.length; i < len; i++){
    // blah blah
}

böylece arr.lengthher seferinde hesaplanmayacaktır.

Diğerleri, derleyicinin buna bir miktar optimizasyon yapacağını söyler, böylece şunları yazabilirsiniz:

for(var i=0; i < arr.length; i++){
    // blah blah
}

Sadece pratikte hangisinin en iyi yol olduğunu bilmek istiyorum?


1
dizi döngü ile uğraşırken de bir göz atmaya değer: jsperf.com/array-loop-var-caching
cloakedninjas

@ wong2 Tthis kriter gelen Browserdiet alternatiflerin daha eksiksiz bir koleksiyona sahiptir.
Domi


Önceki jsben üzerinde geliştirildi: jsben.ch/#/R6LbS
Corbfon

for ... ofDöngüyü bu yarışmaya tanıtabilir miyiz ? Sözdizimi, önbellek kullanmadan bir for döngüsünden bile daha kolay görünüyor ve döngüler için kullanımına geçmem gerekip gerekmediğini bilmek istiyorum.
programmerRaj

Yanıtlar:


339

Bu testi en modern tarayıcılarla yaptıktan sonra ...

http://jsben.ch/dyM52

Şu anda , en hızlı döngü şekli (ve bence en sözdizimsel olarak açık).

uzunluk önbellekli döngü için standart

for (var i = 0, len = myArray.length; i < len; i++) {

}

Bunun kesinlikle JavaScript motoru geliştiricilerini alkışladığım bir durum olduğunu söyleyebilirim. Bir çalışma zamanı akıllılık için değil , netlik için optimize edilmelidir .


6
İlginç bir şekilde, IE9'da bu daha hızlıdır: (var i = 0, len = myArray.length; i <len; ++ i) için postfix yerine {} // önek incr
Christopher Bennage

4
Diğer kullanım nedenleri için bkz. Ön ek operatörlerini postfix yerine tercih etme++i .
Bennett McElwee

4
@BennettMcElwee'nin önerdiği gibi önek operatörü kullanarak test ettim ve biraz daha hızlı çalışır: for(var i=0, len=myArray.length; i<len; ++i) Kontrol jsperf.com/caching-array-length/84
victmo

21
Bu döngüyü kullanırken dikkatli olmalısınız. Kullanmaya başladım ve yaptığım bir hata nedeniyle hatayı izlemek zor oldu. Böyle iki döngüyü iç içe yerleştirirseniz: jsfiddle.net/KQwmL/1 . Değişken'i iki döngüde farklı bir şekilde adlandırmaya dikkat etmelisiniz, aksi takdirde ikinci döngü ilk len'in üzerine yazacaktır.
Rui Marques

6
@WillshawMedia Tek bir deyimle birden çok değişken bildirebilirsiniz var. Nasıl yazıldığını, lenaslında önerdiğiniz gibi kapsamlıdır.
jondavidjohn

90

Bir javascript dizisinde döngü yapmanın en hızlı yolu:

var len = arr.length;
while (len--) {
    // blah blah
}

Tam karşılaştırma için http://blogs.oracle.com/greimer/entry/best_way_to_code_a adresine bakın.


1
Kullanmayı unutmayın var(başka lenbir global değişken haline gelir). Ayrıca, daha fazla döngü karşılaştırması için jsperf.com/loops adresine bakın .
Mathias Bynens

22
Bu cevabın dayandığı blog yazısı şu anda neredeyse 4 yaşında ve o zamanki js motorlarında çok şey değişti, güncellenmiş bir karşılaştırma için aşağıdaki cevabımı görün.
jondavidjohn

1
@Jondavidjohn ile hemfikirim. Bu kodu test ettim ve daha az verimli olduğu ortaya çıktı ... Kontrol jsperf.com/caching-array-length/84
victmo

Yukarıdaki cevap neredeyse evrensel olarak (tarayıcılar arasında) bir for-loop'tan çok daha yavaştır. Kabul edilen yanıttaki JSPerf bağlantısına bakın. Harika bir utanç, çünkü son derece okunabilir IMO.
Letharion

3
@Jondavidjohn 'Aşağıdaki cevabım' ile ne demek istediğinizi 'yukarıdaki cevabım' olduğunu tahmin ediyorum.
Shanimal

40

Haziran 2016 itibariyle, en son Chrome'da bazı testler yapma (Mayıs 2016'da tarayıcı pazarının% 71'i ve artma):

  • En hızlı döngü, gerçekten benzer performans sağlayan önbellek uzunluğu olan ve olmayan bir for döngüsüdür . (Önbelleğe alınmış uzunluğa sahip for döngüsü bazen önbelleğe alma olmadankinden daha iyi sonuçlar verir, ancak fark neredeyse önemsizdir, bu da motorun zaten standart ve en önbelleksiz döngü için en uygun olanına göre optimize edilmiş olabileceği anlamına gelir).
  • Azaltılmış while döngüsü, for döngüsünün yaklaşık 1,5 katı kadar yavaştı.
  • Geri arama işlevi (standart forEach gibi) kullanan bir döngü, for döngüsünden yaklaşık 10 kat daha yavaştır.

Bu iş parçacığının çok eski olduğuna ve programcıların uzunluğunu önbelleğe almaları veya daha iyi performans elde etmek için azalmalarıyla ters çaprazlama kullanmaları gerektiğini düşünmek için yanıltıcı olduğuna inanıyorum. Bu nedenle, şunu tavsiye ederim:

  • Uygulamanız çok sayıda öğeyi yineliyorsa veya döngü kodunuz sık kullanılan bir işlevin içindeyse, yanıt için basit bir çözümdür:

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
  • Uygulamanız gerçekten çok sayıda öğe arasında yineleme yapmıyorsa veya burada ve orada küçük yinelemeler yapmanız gerekiyorsa, standart forEach geri aramasını veya seçtiğiniz JS kitaplığınızdan benzer bir işlevi kullanmak daha anlaşılabilir ve hatalara daha az eğilimli olabilir. dizin değişkeni kapsamı kapalıdır ve dizi değerine doğrudan erişerek köşeli ayraç kullanmanıza gerek yoktur:

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
  • Milyarlarca satır boyunca yineleme yaparken gerçekten birkaç milisaniye çizmeniz gerekiyorsa ve dizinizin uzunluğu süreç boyunca değişmiyorsa, for döngünüzdeki uzunluğu önbelleğe almayı düşünebilirsiniz. Bugünlerde bunun gerçekten gerekli olmadığını düşünmeme rağmen:

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }

Hayır! jsbench.github.io/#67b13d4e78cdd0d7a7346410d5becf12 , en hızlısının "Ters döngü, örtük karşılaştırma, satır içi kod" (105,221 ops / sn) olduğunu gösterirken "Döngü, önbelleğe alınan değer, satır içi kod" yalnızca 76,635 ops / sn (Chrome 38.0.2125.111) )
Fr0sT

@ Fr0sT Benchmarkınız dizileri dizin 1'den <= uzunluğa çeviren farklı bir senaryodur. Tabii ki bu farklı sonuçlara yol açacaktır. <Uzunluklu sıfır tabanlı dizileri değiştirmeyi denerseniz - ki bu her zamanki senaryodur - sonuçların normal bir "for" döngüsü ile (önbellek uzunluğu biraz daha hızlı olacak şekilde) daha iyi optimize edildiğini keşfedeceksiniz.
CGodo

Kyopaxa kriterleri (0 <= i <uzunluk) olarak değiştirdi, sonuçlar aynı. "Ters döngü, örtük karşılaştırma, işlev çağrısı" 365 kops / sn, "Döngü, önbellek değeri, satır içi kod" puanlama 350 kops / sn (FF 51)
Fr0sT

@ Fr0sT Sıfır tabanlı önbelleğe alınmış for-loop'ları eşit bir karşılaştırma yapmadan değiştirirseniz, örneğin loop'lar for(let i=0, j=array.length; i < j; i++)için ileri önemli ölçüde hızlanır. Birkaç testte kazandım, çoğu hata veya ters döngü marjındaydı.
Isaac B

1
@IsaacB ve hepsi, üzgünüm tezgah oldukça yanlış olduğunu fark etmedim - tüm doğrudan döngüler yinelenen 1..length ise ters döngüler yinelenen length..0 (arr [uzunluk] öğesi geçersiz). Testleri düzelttim ve şu sonuçları gösteriyorlar: "Döngü, satır içi kod" 360,616 ops / sn ±% 0,27, "Döngü, önbellek değeri, satır içi kod" 345,786 ops / sn ±% 2,18 (Sic!) "Ters döngü, örtük karşılaştırma, satır içi kod "322,640 ops / sn ±% 2,90 (!!!). Testler FF51 tarafından gerçekleştirildi. Yeni tezgah burada jsbench.github.io/#6bdfcd2692ba80c16a68c88554281570 . Bu yüzden, döngüleri çirkinleştirmenin bir anlamı yok gibi görünüyor.
Fr0sT

31

Sipariş önemli değilse, bu stili tercih ederim:

for(var i = array.length; i--; )

Uzunluğu önbelleğe alır ve yazmak çok daha kısadır. Ancak dizi üzerinde ters sırayla yinelenir.


6
Sadece öldürdün.
Vignesh Raja

ihtiyacım yok i> = 0 ;?
MarwaAhmad

3
@MarwaAhmad: No. i--bir sayı döndürür ve sayı bir kez 0koşul olduğu falseiçin olur Boolean(0) === false.
Felix Kling

31

Sadece 2018, bu yüzden bir güncelleme güzel olabilir ...

Ve kabul edilen cevaba gerçekten katılmıyorum . Farklı tarayıcılarda kaybolur. bazıları forEachdaha hızlı, bazıları for-loopve bazıları while burada tüm yöntem için bir kriter http://jsben.ch/mW36e

arr.forEach( a => {
  // ...
}

ve for-loop'u bir sürü görebildiğiniz için for(a = 0; ... ), 'var' değişkenleri olmadan küresel olarak tanımlanacağını ve bunun hızı önemli ölçüde etkileyebileceğini ve yavaşlayacağını belirtmek gerekir.

Duff'ın cihazı operada daha hızlı çalışıyor ancak firefox'ta çalışmıyor

var arr = arr = new Array(11111111).fill(255);
var benches =     
[ [ "empty", () => {
  for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
  for(var a = 0, l = arr.length; a < l; ++a)
    var b = arr[a] + 1;
}]
, ["for-loop++", () => {
  for(var a = 0, l = arr.length; a < l; a++)
    var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
  for(var a = 0; a < arr.length; ++a )
    var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
  for(var a = arr.length - 1; a >= 0; --a )
    var b = arr[a] + 1;
}]
,["while-loop", () => {
  var a = 0, l = arr.length;
  while( a < l ) {
    var b = arr[a] + 1;
    ++a;
  }
}]
, ["reverse-do-while-loop", () => {
  var a = arr.length - 1; // CAREFUL
  do {
    var b = arr[a] + 1;
  } while(a--);   
}]
, ["forEach", () => {
  arr.forEach( a => {
    var b = a + 1;
  });
}]
, ["for const..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( const a in ar ) {
    var b = a + 1;
  }
}]
, ["for let..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( let a in ar ) {
    var b = a + 1;
  }
}]
, ["for var..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( var a in ar ) {
    var b = a + 1;
  }
}]
, ["Duff's device", () => {
  var len = arr.length;
  var i, n = len % 8 - 1;

  if (n > 0) {
    do {
      var b = arr[len-n] + 1;
    } while (--n); // n must be greater than 0 here
  }
  n = (len * 0.125) ^ 0;
  if (n > 0) { 
    do {
      i = --n <<3;
      var b = arr[i] + 1;
      var c = arr[i+1] + 1;
      var d = arr[i+2] + 1;
      var e = arr[i+3] + 1;
      var f = arr[i+4] + 1;
      var g = arr[i+5] + 1;
      var h = arr[i+6] + 1;
      var k = arr[i+7] + 1;
    }
    while (n); // n must be greater than 0 here also
  }
}]];
function bench(title, f) {
  var t0 = performance.now();
  var res = f();
  return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
  // Here if you forget to put 'var' so variables'll be global
  for(a = 0, l = arr.length; a < l; ++a)
     var b = arr[a] + 1;
});
var times = benches.map( function(a) {
                      arr = new Array(11111111).fill(255);
                      return [a[0], bench(...a)]
                     }).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
  `<div>` +
    `<span>${title} &nbsp;</span>` +
    `<span style="width:${3+n/2}%">&nbsp;${Number(time.toFixed(3))}msec</span>` +
  `</div>`;

var strRes = times.map( t => template(...t) ).join("\n") + 
            `<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {  clear:both   }
body > div > div > span {
  float:left;
  width:43%;
  margin:3px 0;
  text-align:right;
}
body > div > div > span:nth-child(2) {
  text-align:left;
  background:darkorange;
  animation:showup .37s .111s;
  -webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>


3
Muhtemelen demek istedi "ve her yerde çalışıyor ancak Opera Mini" @Maykonn
dube

3
@Maykonn Varsayılan görünümde listelenmeyen, çünkü tüm kullanıcıların% 0,18'i IE8'e sahiptir ve onu desteklemeye çalışırken zaman kaybetmemelisiniz; 2018'de ölü bir at.
dube

1
Dünyadaki tüm kullanıcıları düşünürseniz kesinlikle doğrudur. Ancak, ne yazık ki, dünyanın belirli bölgelerinde IE8 henüz ilgili.
Maykonn

1
Yapabilirsem, sadece farklı tarayıcılar farklı yöntemlerle farklı sonuçlara sahip olmayacak, aynı tarayıcılar farklı girişlerle farklı sonuçlara sahip olacaktır. Küçük bir karışık dizi olmayacakken, sadece büyük bir Sayı Dizisi çok optimize edilecektir.
19'da Kaiido

1
@Tahlil Teşekkürler.
nullqube

19

2014 Whilegeri döndü

Sadece mantıklı düşünün.

Şuna bak

for( var index = 0 , length = array.length ; index < length ; index++ ) {

 //do stuff

}
  1. En az 2 değişken (dizin, uzunluk) oluşturmanız gerekir
  2. Dizinin uzunluktan küçük olup olmadığını kontrol etmeniz gerekiyor
  3. Dizini artırmanız gerekiyor
  4. forDöngü 3 parametre vardır

Şimdi bana bunun neden daha hızlı olması gerektiğini söyleyin:

var length = array.length;

while( --length ) { //or length--

 //do stuff

}
  1. Bir değişken
  2. Kontrol yok
  3. endeks azalır (Makineler bunu tercih eder)
  4. while sadece bir parametresi var

Chrome 28 for döngüsünün zamandan daha hızlı olduğunu gösterdiğinde tamamen kafam karıştı. Bu bir çeşit

"Ah, herkes for döngüsünü kullanıyor, krom için geliştirirken buna odaklanalım."

Ama şimdi, 2014 yılında while döngüsü krom üzerinde. 2 kat daha hızlı, diğer / eski tarayıcılarda her zaman daha hızlıydı.

Son zamanlarda yeni testler yaptım. Şimdi gerçek dünya ortamında bu kısa kodlar hiçbir şeye değmez ve jsperf aslında while döngüsünü düzgün çalıştıramaz, çünkü aynı zamanda zaman alan array.length'i yeniden oluşturmanız gerekir.

jsperf üzerinde bir while döngüsünün gerçek hızını elde edemezsiniz.

kendi özel işlevinizi oluşturmanız ve window.performance.now()

Ve evet ... while döngüsünün daha hızlı olmasının bir yolu yok.

Asıl sorun aslında dom manipülasyonu / oluşturma zamanı / çizim zamanıdır ya da istediğiniz gibi.

Örneğin ben koordinatları ve çarpışmaları hesaplamak için gereken bir tuval sahne var ... Bu 10-200 MicroSeconds (milisaniye değil) arasında yapılır. aslında her şeyi işlemek için milisaniye sürer. DOM'daki gibi.

FAKAT

loopBazı durumlarda for özelliğini kullanmanın başka bir süper performans yolu var ... örneğin bir diziyi kopyalamak / klonlamak için

for(
 var i = array.length ;
 i > 0 ;
 arrayCopy[ --i ] = array[ i ] // doing stuff
);

Parametrelerin ayarına dikkat edin:

  1. While döngüsünde olduğu gibi sadece bir değişken kullanıyorum
  2. Dizinin 0'dan büyük olup olmadığını kontrol etmeniz gerekir;
  3. Gördüğünüz gibi ben 3th parametre içinde şeyler yapmak ve ben de doğrudan dizi içinde azaltmak gibi herkesin kullandığı döngü için normal vs vs farklıdır.

Dedi ki, bu makineleri -

biraz daha kısa yapmak ve bazı işe yaramaz şeyler kaldırmak ve aynı tarzı kullanarak bu yazmayı düşünüyordum yazma:

for(
 var i = array.length ;
 i-- ;
 arrayCopy[ i ] = array[ i ] // doing stuff
);

Daha kısa olsa bile, ibir kez daha kullanmak her şeyi yavaşlatır. Önceki fordöngüden ve 1 / 1'den daha yavaş while.

Not:; olmadan looo için sonra çok önemlidir{}

Ben sadece jsperf komut dosyalarını test etmek için en iyi yolu olmadığını söyledi bile .. ben bu 2 döngü burada ekledi

http://jsperf.com/caching-array-length/40

Ve burada javascript'teki performans hakkında başka bir cevap

https://stackoverflow.com/a/21353032/2450730

Bu cevap, javascript yazmanın etkili yollarını göstermektir. Eğer okuyamıyorsanız, sorun ve javascript http://www.ecma-international.org/ecma-262/5.1/


Bu cevap çok iyi başlıyor . Son birkaç yılın foro zamandan daha hızlı olduğunu fark ettim whileve bir keresinde crome-dev'de tam olarak bahsettiğiniz nedenden dolayı okudum. whileTekrar yetişmek sadece bir zaman meselesi olurdu. Bu noktadan sonra, cevabınızın ilk kısmındaki mantık tutacak (bir kez daha, yay)! Bununla birlikte, Modern uygulamalar artık ecma tarafından belirtilen her adımı katı bir şekilde takip etmemektedir (optimize eder). Artık motorunuz artık en göze çarpan şişe boynu olmadığı için, artık ters döngülerdeki CPU önbellek hatalarını fark edebilirsiniz !
GitaarLAB

Açıklayın, belki cevabı düzeltebilir veya yeni bir şey öğrenebilirim. btw cevap şimdi bir yıldan daha eski ... tarayıcılar her zaman yaptıkları gibi zaman içinde değişmiş olabilir ...
cocco

Bence (--length) kötüdür, çünkü teknik olarak çalışırken 0 yanlış olduğu için, 0 ve yanlış anlamsal olarak konuşan şeyle aynı değildir.
scott.korin

evet ... şimdi eski bir yazı ... ama evet zamanın basitliğini seviyorum. Ve her iki durumda da bahsettiğiniz gibi, ne yazacağınızı bilmeniz gerekir. Diğer tarafta, negatif sayılar arasında döngü yapmaya hiç gerek duymadım.
koko

9
"makineler bunu tercih ediyor", bir çamaşır deterjanı için bir reklamdan bir cümle gibi geliyor
CocoaBean

11

http://jsperf.com/caching-array-length/60

Hazırladığım testin en son revizyonu (eskisini tekrar kullanarak) bir şey gösteriyor.

Önbellek uzunluğu o kadar önemli değildir, ancak zarar vermez.

Yukarıda bağlanan testin her ilk çalıştırması (yeni açılan sekmede) Debian Squeeze 64-bit'imdeki ( masaüstü donanımım ) Chrome, Opera ve Firefox'ta son 4 snippet (grafiklerde 3., 5., 7. ve 10.) en iyi sonuçları verir ). Sonraki çalışmalar oldukça farklı sonuç verir.

Performans açısından sonuçlar basit:

  • Döngü (ileri) ile gidin ve !==yerine kullanarak test edin <.
  • Diziyi daha sonra yeniden kullanmak zorunda shift()kalmazsanız , azaltılmış uzunluktaki ve yıkıcı -ing dizisindeki döngü de etkilidir.

tl; Dr.

Günümüzde (2011.10) aşağıdaki desen en hızlı olanı gibi görünüyor.

for (var i = 0, len = arr.length; i !== len; i++) {
    ...
}

arr.lengthBurada önbelleğe almanın çok önemli olmadığını unutmayın, bu yüzden sadece test edebilirsiniz i !== arr.lengthve performans düşmez, ancak daha kısa kod alırsınız.


Not: Snippet'te shift()sonucuyla birlikte 0. elemente erişmek yerine kullanılabileceğini biliyorum , ancak bir şekilde önceki revizyonu (döngüler sırasında yanlış olan) yeniden kullandıktan sonra ve daha sonra zaten elde edilen sonuçları kaybetmek istemediğimi göz ardı ettim.


Değişken oluşturmak, loop'u let current = arr [i] gibi bir insite oluştururken bir performansı düşürebilir (büyük bellek ayırma)? Yoksa döngüden önce akım beyan etmek daha iyi olur mu? Veya döngü içindeki tüm yerlerde arr [i] kullanın?
Makarov Sergey

8

Saf performansta olduğu gibi "en iyi"? veya performans VE okunabilirlik?

Bir önbellek ve ++ önek operatörü kullanan saf performans "en iyi" (verilerim: http://jsperf.com/caching-array-length/189 )

for (var i = 0, len = myArray.length; i < len; ++i) {
  // blah blah
}

Önbelleksiz for-loop'un yürütme süresi ve programcı okuma süresinde en iyi denge olduğunu iddia ediyorum. C / C ++ / Java ile başlayan her programcı, bunu okumak zorunda olan bir ms'yi boşa harcamaz

for(var i=0; i < arr.length; i++){
  // blah blah
}

2
Okunabilirlik için +1. Ne kadar iyi lenadlandırılmış olursa olsun , kişi her zaman ilk döngüyü iki kez yapmak zorundadır. İkinci döngünün amacı açıktır.
Josh Johnson

7

** döngü uzunluğu döngü içinde önbellek, birkaç saniye kaçınılması. Dizideki öğelere bağlı olarak dizide daha fazla öğe varsa Ms zamanına göre büyük bir fark vardır *

**

sArr; //Array[158];

for(var i = 0 ; i <sArr.length ; i++) {
 callArray(sArr[i]); //function call
}

***end: 6.875ms***

**

**

sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
  callArray(sArr[i]); //function call
}

***end: 1.354ms***

**


6

Bu şimdiye kadarki en hızlı yol gibi görünüyor ...

var el;
while (el = arr.shift()) {
  el *= 2;
}

Bunun diziyi tüketeceğini, yiyeceğini ve hiçbir şey bırakmayacağını göz önünde bulundurun ...


2
arr.shift();bunun yerine arr.pop() dizi tersine kaçınılabilir.
Tintu C Raju

1
@Gargaroz, örneğin bir sohbet servisi veya ürün kataloğundaki öğeler gibi bir web servisinden JSON alıyorsanız. Diziyi bir kez kullanmanız gerektiğinde başka bir durum, örneğin, aralıklı olarak birçok koordinat alan bir grafik olabilir. Birçok örnek var.
Sergio

Harika, açıklama için teşekkür ederim, çok naziksiniz; beni bu tür döngüden yararlanmak için başka örnekler bulabileceğim yöne yönlendirebilir misin?
Şubat'ta Gargaroz

1
Şu anda Chrome 53 ve Firefox 48'de en yavaş yaklaşımlardan biri
perfjs.info/array-iteration

1
@Alireza katılıyorum, cevabımda da bunun için bir yorumum var.
Sergio

4

2017 yılı .

Bazı testler yaptım.

https://jsperf.com/fastest-way-to-iterate-through-an-array/

whileYöntem, Chrome'da en hızlı yöntem gibi görünüyor .

Sol eksiltme gibi görünüyor ( --i) çok daha hızlı diğerlerinden (daha ++i, i--, i++Firefox'ta).

Bu yaklaşım ortalama bir açlıktır. Ancak diziyi ters sırayla yineler.

let i = array.length;
while (--i >= 0) {
    doSomething(array[i]);
}

İlerleme sırası önemliyse, bu yaklaşımı kullanın.

let ii = array.length;
let i = 0;
while (i < ii) {
    doSomething(array[i]);
    ++i;
}

3
Anahtar kelimeyi kullanarak, letaslında döngü performansı yerine kapsam oluşturma performansını karşılaştırıyorsunuzdur. Kullanma let i = 0, ii = array.lengthsenin içinde fordöngüler içinde bu değişkenlerin için yeni bir kapsam yaratacaktır forblokta. Sizin whileörnekler içindeki değişkenler için yeni bir kapsam oluşturmayın whileblok ve daha hızlı olmasının nedeni budur. Döngüler varyerine kullanmak letistiyorsanız, döngülerin 2017'de hala ne kadar hızlı olduğunu, ancak daha okunabilir olduğunu göreceksiniz.
CGodo

İşte bahsettiğim şeyin bir jsperf: jsperf.com/javascript-loop-testing-let-vs-var
CGodo

Bu yalnızca Chrome'daki bir sorundur. Diğer Tarayıcılarda varve letaynı performansa sahip - stackoverflow.com/a/32345435/1785975
SeregPie

İlginç. Her neyse, " whileChrome'da daha hızlı olma " ifadesini doğru bulmuyorum . Yalnızca letChrome'daki söz konusu anahtar kelimenin performans sorunları nedeniyle kullanılıyorsa . varDiğer tarayıcılarla veya diğer tarayıcılarla kullanılıyorsa forve whilehemen hemen aynı forise, karşılaştırmaya bağlı olarak bazen daha da hızlıdır ve daha kompakt ve okunabilir imho'dur.
CGodo

2

Her zaman ilk stilde yazıyorum.

Bir derleyici diziler için optimize etmek için yeterince akıllı olsa da, burada DOMNodeList veya hesaplanmış uzunluğa sahip karmaşık bir nesne kullanıyorsanız hala akıllı mı?

Dizilerle ilgili sorunun ne olduğunu biliyorum, ancak bence tüm döngülerinizi tek bir stilde yazmak iyi bir uygulamadır.


1
var arr = []; // The array
var i = 0;
while (i < arr.length) {
    // Do something with arr[i]
    i++;
}

i ++, ++ i, --i ve i-- 'den daha hızlıdır

Ayrıca, i'ye erişmeniz gereken son kez arr [i ++] yaparak son satırı kaydedebilirsiniz (ancak bu hata ayıklamak zor olabilir).

Burada test edebilirsiniz (diğer döngü testleriyle): http://jsperf.com/for-vs-whilepop/5


1
Şu anda Chrome 53'te bu doğru, ancak Firefox 48 aynı hıza sahip
perfjs.info/array-iteration


1

Eylül 2017 itibarı ile bu jsperf testleri , Chrome 60'da en iyi performans gösteren aşağıdaki modeli göstermektedir:

function foo(x) {
 x;
};
arr.forEach(foo);

Herkes üreyebilir mi?


Evet, en hızlı gibi görünüyor, Ancak bunu IE11'de çalıştırmayı deneyin ve bu seçenekler en yavaş olanlardır. Ve Firefox 55.03'te 'eski yakalanmış önbellekli len', 3.3k kromla karşılaştırıldığında şaşırtıcı bir performans olan 12mil'e ulaşıyor. Tüm tarayıcılarda performansta tutarlı olmak için her tarayıcı için en hızlı ortalama döngüyü kullanmalısınız.
Plippie

0

Büyük bir dizi yinelemek için başka yollar denedim ve dizi uzunluğu yarıya indirmek ve sonra tek bir döngüde her iki yarısı yineleme daha hızlı olduğunu öğrendim. Bu performans farkı, büyük diziler işlenirken görülebilir .

var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
   firstHalfLen = Math.ceil(halfLen);
   secondHalfLen=Math.floor(halfLen);
}
else
{
   firstHalfLen=halfLen;
   secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
    firstHalfCOunter < firstHalfLen;
    firstHalfCOunter++)
{
  if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
  {
    count2+=1;
  }
  if(secondHalfCounter < arrayLength)
  {
    if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
    {
        count2+=1;
    }
    secondHalfCounter++; 
  }
}

Yukarıdaki yöntem için döngü VS önbelleğe alınmış uzunluğu arasında bazı performans karşılaştırması (timer.js kullanarak).

http://jsfiddle.net/tejzpr/bbLgzxgo/




0

İlmek döngü için biraz daha hızlı.

var len = arr.length;
while (len--) {
    // blah blah
}

Bunun yerine while döngüsü kullan



-1

Bildiğim en şık çözüm harita kullanmak.

var arr = [1,2,3];
arr.map(function(input){console.log(input);});

46
Soru bir döngüden tekrarlamanın en yavaş yolunu
istemiyor

-1

Bunu dene:

var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}

-1

Bir dizide döngü yapmanın en hızlı yolu filtreyi kullanmaktır. Filter () yöntemi, sağlanan işlev tarafından uygulanan sınamayı geçen tüm öğeleri içeren yeni bir dizi oluşturur.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

const words = ['Floccinaucinihilipilification', 'limit', 'elite', 'Hippopotomonstrosesquipedaliophobia', 'destruction', 'present'];

const result = words.filter(word => word.length > 6);

console.log(new Date(), result);

Deneyimlerime göre, her zaman filtreleri, haritayı vb. Tercih ederim.


Soru, diziyi yeni bir diziye kopyalamadan en kısa sürede dizi üzerinden yineleme yapmaktır.
Rahul Kadukar

-1

2019 itibariyle WebWorker daha popüler olmuştur, büyük veri kümeleri için WebWorker'ı çok çekirdekli işlemcilerden tam olarak yararlanarak çok daha hızlı işlemek için kullanabiliriz.

WebWorker'ın veri işleme için kullanımını daha kolay hale getiren Parallel.js de var .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.