Cách nhanh nhất để lặp qua một mảng trong JavaScript là gì?


248

Tôi đã học được từ những cuốn sách mà bạn nên viết cho vòng lặp như thế này

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

vì vậy arr.lengthsẽ không được tính mỗi lần

Những người khác nói rằng trình biên dịch sẽ thực hiện một số tối ưu hóa cho điều này, vì vậy bạn chỉ có thể viết:

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

Tôi chỉ muốn biết đó là cách tốt nhất trong thực tế?


1
cũng đáng xem khi xử lý vòng lặp mảng: jsperf.com/array-loop-var-caching
cloainedninjas

@ wong2 Điểm chuẩn Tthis từ Browserdiet có bộ sưu tập thay thế hoàn chỉnh hơn.
Domi


Được cải thiện trên jsben trước: jsben.ch/#/R6LbS
Corbfon

Chúng tôi có thể giới thiệu for ... ofvòng lặp cho cuộc thi này? Cú pháp có vẻ dễ dàng hơn sau đó là một vòng lặp for mà không cần lưu vào bộ nhớ cache và tôi muốn biết liệu tôi có nên chuyển sang sử dụng cho các vòng lặp hay không.
lập trình

Câu trả lời:


339

Sau khi thực hiện thử nghiệm này với hầu hết các trình duyệt hiện đại ...

http://jsben.ch/dyM52

Hiện nay , dạng vòng lặp nhanh nhất (và theo tôi là rõ ràng nhất về mặt cú pháp).

một tiêu chuẩn cho vòng lặp với bộ nhớ đệm chiều dài

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

}

Tôi muốn nói rằng đây chắc chắn là một trường hợp tôi hoan nghênh các nhà phát triển công cụ JavaScript. Một thời gian chạy nên được tối ưu hóa cho rõ ràng , không thông minh .


6
Thật thú vị, trong IE9, điều này nhanh hơn: for (var i = 0, len = myArray.length; i <len; ++ i) {} // tiền tố tăng, thay vì tiền tố
Christopher Bennage

4
Xem Ưu tiên các toán tử tiền tố hơn postfix để biết các lý do khác để sử dụng ++i.
Bennett McElwee

4
Tôi đã thử nghiệm sử dụng toán tử tiền tố như @BennettMcElwee đề xuất và nó chạy nhanh hơn một chút: for(var i=0, len=myArray.length; i<len; ++i) Kiểm tra jsperf.com/caching-array-length/84
victmo 22/03 '

21
Bạn phải cẩn thận khi sử dụng vòng lặp này. Tôi bắt đầu sử dụng nó và gặp một lỗi khó theo dõi vì một lỗi tôi đã mắc phải. Nếu bạn lồng hai vòng như thế này: jsfiddle.net/KQwmL/1 . Bạn phải cẩn thận đặt tên var len khác nhau trong hai vòng, nếu không vòng lặp thứ hai sẽ ghi đè lên len thứ nhất.
Rui Marques

6
@WillshawMedia Bạn có thể khai báo nhiều biến bằng một varcâu lệnh. Làm thế nào nó được viết, lenthực sự là phạm vi như bạn đề nghị.
jondavidjohn

90

Cách nhanh nhất tuyệt đối để lặp qua một mảng javascript là:

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

Xem http://bloss.oracle.com/greimer/entry/best_way_to_code_a để so sánh đầy đủ


1
Đừng quên sử dụng var(khác lentrở thành một biến toàn cục). Ngoài ra, hãy xem jsperf.com/loops để biết thêm điểm chuẩn vòng lặp.
Mathias Bynens

22
Bài đăng trên blog câu trả lời này dựa trên hiện đã gần 4 tuổi và rất nhiều thay đổi trong công cụ js trong thời gian đó, hãy xem câu trả lời của tôi dưới đây để so sánh cập nhật.
jondavidjohn

1
Tôi đồng ý với @jondavidjohn. Tôi đã thử nghiệm mã này và hóa ra nó kém hiệu quả hơn ... Kiểm tra jsperf.com/caching-array-length/84
victmo 22/03 '

Câu trả lời trên hầu như phổ biến (trên các trình duyệt) chậm hơn nhiều so với vòng lặp for. Xem liên kết JSPerf trong câu trả lời được chấp nhận. Đó là một sự xấu hổ lớn, vì nó là IMO cực kỳ dễ đọc.
Letharion

3
Tôi đoán @jondavidjohn rằng ý của bạn là 'câu trả lời của tôi dưới đây' là 'câu trả lời của tôi ở trên' lol.
Shanimal

40

Kể từ tháng 6 năm 2016 , thực hiện một số thử nghiệm trên Chrome mới nhất (71% thị trường trình duyệt vào tháng 5 năm 2016 và ngày càng tăng):

  • Vòng lặp nhanh nhất là vòng lặp for , cả có và không có bộ nhớ đệm mang lại hiệu suất thực sự tương tự. (Vòng lặp for với độ dài được lưu trong bộ nhớ cache đôi khi mang lại kết quả tốt hơn so với vòng lặp không có bộ đệm, nhưng sự khác biệt gần như không đáng kể, điều đó có nghĩa là động cơ có thể đã được tối ưu hóa để ưu tiên cho vòng lặp tiêu chuẩn và có lẽ đơn giản nhất cho vòng lặp mà không cần lưu vào bộ đệm).
  • Vòng lặp while có số giảm chậm hơn khoảng 1,5 lần so với vòng lặp for.
  • Một vòng lặp sử dụng chức năng gọi lại (như forEach tiêu chuẩn), chậm hơn khoảng 10 lần so với vòng lặp for.

Tôi tin rằng chủ đề này quá cũ và khiến các lập trình viên hiểu lầm rằng họ cần lưu trữ bộ nhớ cache hoặc sử dụng các chuỗi đảo ngược có độ phân giải để đạt được hiệu suất tốt hơn, viết mã dễ đọc hơn và dễ bị lỗi hơn so với vòng lặp đơn giản. Do đó, tôi khuyên bạn nên:

  • Nếu ứng dụng của bạn lặp lại nhiều mục hoặc mã vòng lặp của bạn nằm trong một hàm được sử dụng thường xuyên, thì vòng lặp đơn giản là câu trả lời:

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
  • Nếu ứng dụng của bạn không thực sự lặp đi lặp lại qua nhiều mục hoặc bạn chỉ cần thực hiện các bước lặp nhỏ ở đây và đó, thì sử dụng hàm gọi lại forEach tiêu chuẩn hoặc bất kỳ chức năng tương tự nào từ thư viện JS của bạn có thể dễ hiểu hơn và ít bị lỗi hơn, vì phạm vi biến chỉ mục được đóng và bạn không cần sử dụng dấu ngoặc, truy cập trực tiếp vào giá trị mảng:

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
  • Nếu bạn thực sự cần phải cào vài mili giây trong khi lặp lại hàng tỷ hàng và độ dài của mảng không thay đổi trong suốt quá trình, bạn có thể xem xét lưu vào bộ đệm trong vòng lặp for của mình. Mặc dù tôi nghĩ rằng điều này thực sự không cần thiết ngày nay:

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

Không. jsbench.github.io / )
Fr0sT

@ Fr0sT Điểm chuẩn của bạn là một kịch bản khác, đi qua các mảng từ chỉ số 1 đến <= chiều dài. Tất nhiên điều này sẽ dẫn đến kết quả khác nhau. Nếu bạn thử duyệt qua các mảng dựa trên zero với <length - có vẻ như đó là kịch bản thông thường - bạn sẽ phát hiện ra rằng kết quả được tối ưu hóa tốt hơn với vòng lặp "for" bình thường (với độ dài được lưu trong bộ nhớ cache nhanh hơn một chút).
CGodo

Kyopaxa đã thay đổi điểm chuẩn thành (0 <= i <length), kết quả là như nhau. "Vòng lặp ngược, so sánh ngầm, gọi hàm" đã ghi được 365 kops / giây, trong khi "Vòng lặp, giá trị được lưu trong bộ đệm, mã được in" đã ghi được 350 kops / giây (FF 51)
Fr0sT

@ Fr0sT nếu bạn thay đổi các vòng lặp được lưu trong bộ nhớ cache dựa trên số 0 mà không có sự so sánh bằng nhau, chẳng hạn như for(let i=0, j=array.length; i < j; i++)chuyển tiếp cho các vòng lặp tăng tốc đáng kể. Trong một vài thử nghiệm tôi đã chạy nó đã thắng, hầu hết nó nằm trong phạm vi lỗi hoặc vòng lặp ngược.
Isaac B

1
@IsaacB và tất cả, xin lỗi, tôi không nhận thấy rằng băng ghế dự bị khá không chính xác - tất cả các vòng lặp trực tiếp lặp lại 1..length trong khi các vòng lặp ngược lặp lại chiều dài..0 (mục [chiều dài] không hợp lệ). Tôi đã sửa các thử nghiệm và bây giờ chúng hiển thị các kết quả sau: "Vòng lặp, mã nội tuyến" 360,616 ops / giây ± 0,27%, "Vòng lặp, giá trị được lưu trong bộ nhớ cache, mã nội tuyến" 345,786 ops / giây ± 2,18% (Sic!) "Vòng lặp ngược, so sánh ngầm, mã nội tuyến "322,640 ops / giây ± 2,90% (!!!). Các thử nghiệm đã được thực hiện bởi FF51. Băng ghế mới ở đây jsbench.github.io/#6bdfcd2692ba80c16a68c88554281570 . Vì vậy, có vẻ như không có ý nghĩa trong việc làm xấu đi các vòng lặp.
Fr0sT

31

Nếu thứ tự không quan trọng, tôi thích phong cách này:

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

Nó lưu trữ độ dài và ngắn hơn nhiều để viết. Nhưng nó sẽ lặp lại trên mảng theo thứ tự ngược lại.


6
Bạn vừa giết nó.
Vignesh Raja

bạn không cần i> = 0;?
MarwaAhmad

3
@MarwaAhmad: Số i--trả về một số và một khi số đó là 0điều kiện là falsebởi vì Boolean(0) === false.
Felix Kling

30

Chỉ là năm 2018 nên một bản cập nhật có thể tốt ...

Và tôi thực sự phải không đồng ý với câu trả lời được chấp nhận . Nó trì hoãn trên các trình duyệt khác nhau. một số làm forEachnhanh hơn, một số for-loopvà một số while ở đây là điểm chuẩn cho tất cả phương thức http://jsben.ch/mW36e

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

và vì bạn có thể thấy rất nhiều vòng lặp for for(a = 0; ... )đáng để đề cập rằng không có biến 'var' sẽ được xác định trên toàn cầu và điều này có thể ảnh hưởng đáng kể đến tốc độ nên sẽ chậm.

Thiết bị của Duff chạy nhanh hơn trên opera nhưng không phải trong firefox

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
@Maykonn có lẽ bạn muốn nói "và nó hoạt động ở mọi nơi trừ Opera Mini"
dube

3
@Maykonn Không được liệt kê trong chế độ xem mặc định vì 0,18% tất cả người dùng có IE8 và bạn không nên lãng phí thời gian để cố gắng hỗ trợ nó; năm 2018 đó là một con ngựa chết.
dube

1
Điều đó hoàn toàn đúng nếu bạn xem xét tất cả người dùng trên toàn thế giới. Nhưng, thật không may, trong các phần cụ thể của thế giới IE8 vẫn có liên quan.
Maykonn

1
Nếu tôi có thể, không chỉ các trình duyệt khác nhau sẽ có kết quả khác nhau với các phương pháp khác nhau, mà các trình duyệt giống nhau sẽ có kết quả khác nhau với các đầu vào khác nhau. Một mảng số lượng lớn chỉ được tối ưu hóa, trong khi một mảng nhỏ sẽ không được.
Kaiido

1
@Tahlil Cảm ơn.
nullqube

19

2014 đã Whiletrở lại

Chỉ cần suy nghĩ hợp lý.

Nhìn cái này

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

 //do stuff

}
  1. Cần tạo ít nhất 2 biến (chỉ mục, độ dài)
  2. Cần kiểm tra nếu chỉ số nhỏ hơn chiều dài
  3. Cần tăng chỉ số
  4. các forvòng lặp có 3 thông số

Bây giờ hãy nói cho tôi tại sao điều này nên nhanh hơn:

var length = array.length;

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

 //do stuff

}
  1. Một biến
  2. Không kiểm tra
  3. chỉ số giảm (Máy thích hơn)
  4. while chỉ có một tham số

Tôi hoàn toàn bối rối khi Chrome 28 cho thấy vòng lặp for nhanh hơn thời gian. Cái này phải có một số loại

"Uh, mọi người đang sử dụng vòng lặp for, hãy tập trung vào điều đó khi phát triển cho chrome."

Nhưng bây giờ, vào năm 2014, vòng lặp while đã trở lại trên chrome. nó nhanh hơn 2 lần, trên các trình duyệt khác / cũ hơn, nó luôn nhanh hơn.

Gần đây tôi đã thực hiện một số thử nghiệm mới. Bây giờ trong thế giới thực, các mã ngắn đó không có giá trị gì và jsperf thực sự không thể thực thi đúng vòng lặp while, bởi vì nó cần phải tạo lại mảng.length cũng mất thời gian.

bạn không thể có được tốc độ thực của vòng lặp while trên jsperf.

bạn cần tạo chức năng tùy chỉnh của riêng mình và kiểm tra xem với window.performance.now()

Và vâng ... không có cách nào vòng lặp while đơn giản là nhanh hơn.

Vấn đề thực sự là thao tác dom / thời gian kết xuất / thời gian vẽ hoặc tuy nhiên bạn muốn gọi nó.

Ví dụ, tôi có một cảnh canvas trong đó tôi cần tính toán tọa độ và va chạm ... điều này được thực hiện trong khoảng 10-200 MicroSeconds (không phải mili giây). nó thực sự mất nhiều mili giây để hiển thị mọi thứ. Như trong DOM.

NHƯNG

Có một cách siêu hiệu quả khác sử dụng for looptrong một số trường hợp ... ví dụ để sao chép / sao chép một mảng

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

Lưu ý thiết lập các tham số:

  1. Tương tự như trong vòng lặp while tôi chỉ sử dụng một biến
  2. Cần kiểm tra nếu chỉ số lớn hơn 0;
  3. Như bạn có thể thấy cách tiếp cận này khác với vòng lặp thông thường mà mọi người sử dụng, vì tôi làm công cụ bên trong tham số thứ 3 và tôi cũng giảm trực tiếp bên trong mảng.

Nói rằng, điều này xác nhận rằng các máy như -

viết rằng tôi đã suy nghĩ để làm cho nó ngắn hơn một chút và loại bỏ một số thứ vô dụng và viết cái này bằng cách sử dụng cùng một phong cách:

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

Ngay cả khi nó ngắn hơn, có vẻ như sử dụng ithêm một lần nữa sẽ làm chậm mọi thứ. Nó chậm hơn 1/5 so với forvòng lặp trước và vòng lặp trước while.

Lưu ý: điều ;này rất quan trọng sau khi không có{}

Ngay cả khi tôi chỉ nói với bạn rằng jsperf không phải là cách tốt nhất để kiểm tra tập lệnh .. tôi đã thêm 2 vòng lặp ở đây

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

Và đây là một câu trả lời khác về hiệu suất trong javascript

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

Câu trả lời này là để hiển thị các cách viết javascript hiệu quả. Vì vậy, nếu bạn không thể đọc được điều đó, hãy hỏi và bạn sẽ nhận được câu trả lời hoặc đọc một cuốn sách về javascript http: //www.ecma-i Intl.org/ecma-262/5.1/


Câu trả lời này bắt đầu rất tốt . Tôi nhận thấy rằng vài năm gần đây fornhanh hơn whilevà tôi đã từng đọc trên crome-dev chính xác là vì lý do bạn đề cập. Nó sẽ chỉ là vấn đề thời gian trước khi whilebắt kịp một lần nữa. Từ thời điểm đó, logic trong phần đầu tiên của câu trả lời của bạn sẽ được giữ lại (một lần nữa, yay)! Tuy nhiên, các triển khai hiện đại không còn cứng nhắc theo từng bước do ecma chỉ định (chúng tối ưu hóa). Vì bây giờ động cơ của bạn không còn là cổ chai đáng chú ý nhất, giờ đây người ta thực sự có thể nhận thấy các lỗi bộ nhớ cache của CPU trong các vòng lặp ngược !
GitaarLAB 17/03/2015

Giải thích, vì vậy có lẽ tôi có thể sửa câu trả lời hoặc học một cái gì đó mới. btw câu trả lời đã hơn một năm tuổi ... trình duyệt có thể đã thay đổi theo thời gian như mọi khi ...
cocco

Theo tôi, trong khi (--length) là xấu bởi vì về mặt kỹ thuật nó hoạt động vì 0 là sai, 0 và sai không thực sự giống như những gì nói về mặt ngữ nghĩa.
scott.korin

vâng ... bây giờ nó là một bài viết cũ hơn ... nhưng vâng tôi yêu sự đơn giản của thời gian. Và chắc chắn khi bạn đề cập đến nó trong cả hai trường hợp, bạn cần biết phải viết gì. Ở phía bên kia, tôi không bao giờ có nhu cầu lặp lại các số âm.
cocco

9
"máy thích cái này" nghe giống như một câu trong quảng cáo về chất tẩy giặt
CocoaBean

11

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

Bản sửa đổi mới nhất của bài kiểm tra mà tôi đã chuẩn bị (bằng cách sử dụng lại bài kiểm tra cũ hơn), cho thấy một điều.

Độ dài bộ nhớ đệm không quan trọng lắm, nhưng nó không gây hại.

Mỗi lần chạy thử nghiệm đầu tiên được liên kết ở trên (trên tab mới mở) cho kết quả tốt nhất cho 4 đoạn mã cuối (thứ 3, 5, 7 và 10 trong bảng xếp hạng) trong Chrome, Opera và Firefox trong Debian Squeeze 64-bit ( phần cứng máy tính để bàn của tôi ). Các lần chạy tiếp theo cho kết quả khá khác nhau.

Kết luận về hiệu suất rất đơn giản:

  • Đi với vòng lặp for (chuyển tiếp) và kiểm tra bằng cách sử dụng !==thay vì <.
  • Nếu bạn không phải sử dụng lại mảng sau đó, thì vòng lặp trên chiều dài giảm dần và shift()mảng phá hủy cũng hiệu quả.

tl; dr

Ngày nay (2011.10) mẫu dưới đây có vẻ là mẫu nhanh nhất.

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

Lưu ý rằng bộ nhớ đệm arr.lengthkhông quan trọng ở đây, vì vậy bạn chỉ có thể kiểm tra i !== arr.lengthvà hiệu suất sẽ không giảm, nhưng bạn sẽ nhận được mã ngắn hơn.


PS: Tôi biết rằng trong đoạn trích với shift()kết quả của nó có thể được sử dụng thay vì truy cập phần tử 0, nhưng bằng cách nào đó tôi đã bỏ qua rằng sau khi sử dụng lại bản sửa đổi trước đó (có lỗi trong vòng lặp) và sau đó tôi không muốn mất kết quả.


Tạo biến kích hoạt vòng lặp như let current = Array [i] có thể làm giảm hiệu suất (cấp phát bộ nhớ lớn)? Hoặc sẽ tốt hơn để khai báo hiện tại trước khi vòng lặp? Hoặc sử dụng mảng [i] ở tất cả các vị trí bên trong vòng lặp?
Makarov Sergey

8

"Tốt nhất" như trong hiệu suất thuần túy? hoặc hiệu suất khả năng đọc?

Hiệu suất thuần túy "tốt nhất" là cái này, sử dụng bộ đệm và toán tử tiền tố ++ (dữ liệu của tôi: http://jsperf.com/caching-array-length/189 )

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

Tôi sẽ lập luận rằng vòng lặp không có bộ đệm là sự cân bằng tốt nhất trong thời gian thực hiện và thời gian đọc của lập trình viên. Mọi lập trình viên bắt đầu với C / C ++ / Java sẽ không lãng phí một ms phải đọc qua cái này

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

2
+1 cho khả năng đọc. Cho dù lenđược đặt tên tốt đến đâu, người ta sẽ luôn phải thực hiện gấp đôi vòng lặp đầu tiên đó. Ý định của vòng lặp thứ hai là rõ ràng.
Josh Johnson

7

** lưu trữ chiều dài mảng bên trong vòng lặp, một vài giây thời gian sẽ bị xóa. Phụ thuộc vào các mục trong mảng nếu có nhiều mục hơn trong mảng có sự khác biệt lớn đối với Ms of time *

**

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

Đây có vẻ là cách nhanh nhất cho đến nay ...

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

Hãy tính đến việc này sẽ tiêu thụ mảng, ăn nó và không để lại gì ...


2
arr.shift();thay vì arr.pop() vậy để đảo ngược mảng có thể tránh được.
Tintu C Raju

1
@Gargaroz nếu bạn đang nhận JSON từ dịch vụ web, ví dụ như dịch vụ trò chuyện hoặc các mục trên danh mục sản phẩm. Một tình huống khác khi bạn chỉ cần sử dụng mảng một lần có thể là một biểu đồ có nhiều tọa độ trên cơ sở xen kẽ. Có rất nhiều ví dụ.
Sergio

Thật tuyệt, cảm ơn bạn đã giải thích, rất tốt của bạn; bạn có thể chỉ cho tôi hướng mà tôi có thể tìm thấy các ví dụ khác để khai thác loại vòng lặp này không?
Gargaroz

1
Hiện tại trong Chrome 53 và Firefox 48, đây là một trong những cách tiếp cận chậm nhất - kiểm tra perfjs.info/array-iteration
Pencroff

1
@Alireza đồng ý, tôi cũng có một nhận xét cho câu trả lời đó.
Sergio

4

Đó là năm 2017 .

Tôi đã thực hiện một số bài kiểm tra.

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

Có vẻ như whilephương pháp này là nhanh nhất trên Chrome.

Trông giống như những sụt lần trái ( --i) là nhanh hơn nhiều so với những người khác ( ++i, i--, i++) trên Firefox.

Cách tiếp cận này là nhịn ăn trung bình. Nhưng nó lặp lại các mảng theo thứ tự đảo ngược.

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

Nếu thứ tự chuyển tiếp là quan trọng, sử dụng phương pháp này.

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

3
Bằng cách sử dụng từ khóa, letbạn thực sự so sánh hiệu suất tạo phạm vi thay vì hiệu suất vòng lặp. Sử dụng let i = 0, ii = array.lengthtrong các forvòng lặp của bạn sẽ tạo ra một phạm vi mới cho các biến đó bên trong forkhối. Các whileví dụ của bạn không tạo ra một phạm vi mới cho các biến trong whilekhối và đó là lý do tại sao chúng nhanh hơn. Nếu bạn sử dụng varthay vì lettrong các vòng lặp của mình, bạn sẽ thấy các vòng lặp vẫn nhanh như thế nào trong năm 2017, nhưng dễ đọc hơn.
CGodo

Đây là một jsperf về những gì tôi đang nói về: jsperf.com/javascript-loop-testing-let-vs-var
CGodo

Đây chỉ là một vấn đề trong Chrome. Trong các Trình duyệt khác varletcó cùng hiệu suất - stackoverflow.com/a/32345435/1785975
SeregPie

Hấp dẫn. Dù sao, tôi không thấy tuyên bố " whilenhanh hơn trong Chrome" chính xác. Chỉ khi sử dụng letdo vấn đề về hiệu suất của từ khóa đó trong Chrome. Nếu sử dụng varhoặc với các trình duyệt khác, forwhilekhá giống nhau, đôi khi forthậm chí còn nhanh hơn tùy thuộc vào điểm chuẩn, và nó nhỏ gọn hơn và dễ đọc hơn.
CGodo

2

Tôi luôn luôn viết theo phong cách đầu tiên.

Ngay cả khi một trình biên dịch đủ thông minh để tối ưu hóa nó cho các mảng, nhưng vẫn thông minh nếu chúng ta đang sử dụng DOMNodeList ở đây hoặc một số đối tượng phức tạp với độ dài tính toán?

Tôi biết câu hỏi về mảng là gì, nhưng tôi nghĩ rằng đó là một cách thực hành tốt để viết tất cả các vòng lặp của bạn theo một phong cách.


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

i ++ nhanh hơn ++ i, --i và i--

Ngoài ra, bạn có thể lưu dòng cuối cùng thực hiện mảng [i ++] lần cuối cùng bạn cần truy cập i (nhưng điều này có thể khó gỡ lỗi).

Bạn có thể kiểm tra nó ở đây (với các bài kiểm tra vòng lặp khác): http://jsperf.com/for-vs-whilepop/5


1
Hiện tại trong Chrome 53 là sự thật, nhưng Firefox 48 có cùng tốc độ - hãy kiểm tra perfjs.info/array-iteration
Pencroff


1

Kể từ tháng 9 năm 2017, các thử nghiệm jsperf này đang hiển thị mẫu sau có hiệu suất cao nhất trên Chrome 60:

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

Có ai có thể sinh sản?


Vâng, nó có vẻ là nhanh nhất, tuy nhiên hãy thử chạy nó trong IE11 và các tùy chọn đó là chậm nhất. Và trong Firefox 55.03, 'len cũ được lưu trong bộ nhớ cache' đã đạt tới 12 triệu, một hiệu suất đáng kinh ngạc so với 3,3k chrome. Để thống nhất về hiệu suất trong tất cả các trình duyệt, bạn nên sử dụng vòng lặp trung bình nhanh nhất cho mọi trình duyệt.
Plippie

0

Tôi đã thử một số cách khác để lặp lại một mảng lớn và phát hiện ra rằng việc giảm một nửa chiều dài mảng và sau đó lặp lại cả hai nửa trong một vòng lặp sẽ nhanh hơn. Sự khác biệt hiệu suất này có thể được nhìn thấy trong khi xử lý các mảng lớn .

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++; 
  }
}

Một số so sánh hiệu suất (sử dụng timer.js) giữa chiều dài được lưu trong bộ nhớ cache cho phương thức VS.

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


0

Một bài kiểm tra jsperf.com khác: http://jsperf.com/fter-reverse-vs-for-cached-length

Vòng lặp while dường như là nhanh nhất. Vấn đề duy nhất là while (--i) sẽ dừng ở 0. Làm thế nào tôi có thể truy cập mảng [0] trong vòng lặp của mình?


2
Nếu bạn làm như vậy while (i--)thì tính trung thực của isẽ được kiểm tra trước khi giảm dần thay vì giảm dần và sau đó kiểm tra tính trung thực.
Justin Fisher


0

Vòng lặp while nhanh hơn một chút so với vòng lặp.

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

Sử dụng vòng lặp while thay thế



-1

Giải pháp tao nhã nhất mà tôi biết là sử dụng bản đồ.

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

46
Câu hỏi không phải là cách nhanh nhất để lặp qua vòng lặp
eoleary

-1

Thử cái này:

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

-1

Cách nhanh hơn để lặp trong một mảng là sử dụng bộ lọc. Phương thức filter () tạo ra một mảng mới với tất cả các phần tử vượt qua kiểm tra được thực hiện bởi hàm được cung cấp.

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);

Từ kinh nghiệm của tôi, tôi luôn thích các bộ lọc, bản đồ, v.v.


Câu hỏi là về việc lặp lại mảng trong khoảng thời gian ngắn nhất không sao chép mảng vào một mảng mới.
Rahul Kadukar

-1

Kể từ năm 2019, WebWorker đã phổ biến hơn, đối với các bộ dữ liệu lớn, chúng ta có thể sử dụng WebWorker để xử lý nhanh hơn nhiều bằng cách sử dụng đầy đủ bộ xử lý đa lõi.

Chúng tôi cũng có Parallel.js giúp WebWorker dễ sử dụng hơn nhiều để xử lý dữ liệu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.