2011-12-31 27 views
38

Với mã nàyTại sao lặp qua một mảng ngược nhanh hơn sau đó chuyển tiếp

var arr = []; 
    for (var i = 0; i < 10000; ++i) { 
     arr.push(1); 
    } 

Tiền đạo

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

ngược

for (var i = arr.length - 1; i >= 0; --i) {; 
} 

cứng Coded F orward

for (var i = 0; i < 10000; ++i) {; 
} 

tại sao backwords nên nhanh hơn nhiều?

Đây là thử nghiệm http://jsperf.com/array-iteration-direction

+6

Lưu ý rằng trường hợp ngược của bạn phải bắt đầu tại 'arr.length-1' và có' i> = 0' thay vì 'i> 0'. – nnnnnn

+1

Tiêu đề gây hiểu lầm. Nó không còn là trường hợp trực tiếp sử dụng arr.length * là * chậm hơn trong các trình duyệt nâng cao. – user2864740

+0

có thể trùng lặp với [Hiệu suất vòng lặp JavaScript - Tại sao phải giảm trình vòng lặp về hướng 0 nhanh hơn gia tăng] (http://stackoverflow.com/q/3520688/1048572) – Bergi

Trả lời

63

Bởi vì phía trước điều kiện của bạn có nhận length tài sản của mỗi lần mảng của bạn, trong khi các điều kiện khác chỉ có để kiểm tra "lớn hơn 0", một nhiệm vụ rất nhanh.

Khi chiều dài mảng của bạn không thay đổi trong vòng lặp, và bạn thực sự nhìn vào ns-Biến, bạn có thể sử dụng

for (var i=0, l=arr.length; i<l; i++) 

BTW: Thay vì for (var i = arr.length; i > 0; --i) bạn có thể sử dụng for (var i = arr.length; i-- > 0;) mà thực sự chạy qua mảng của bạn từ n-1 đến 0, không phải từ n đến 1.

+0

Đúng, đây là cách tôi làm điều đó cho các chức năng tối ưu. Chỉ cần lưu ý rằng nếu mảng là có thể thay đổi (và nó thường không phải là), điều này có thể bỏ qua một hoặc hai tài nguyên. Ví dụ: điều này sẽ không hoạt động nếu bạn đang lặp qua các phần tử mà chính vòng lặp đó đang thêm hoặc xóa. –

+3

bạn thậm chí có thể làm 'cho (...; i--;)' – ajax333221

+0

vì vậy về cơ bản nó có nghĩa là nếu tôi không thay đổi mảng và tôi giữ array.length trong một biến, sau đó tốc độ ngược = tốc độ chuyển tiếp? Ví dụ: var length = array.length; cho (var i = 0; i

8

Bởi vì theo hình thức đầu tiên bạn đang truy cập tài sản length của mảng arr một lần cho mỗi lần lặp, trong khi trong lần thứ hai bạn chỉ làm điều đó một lần.

+0

@samccone - bạn thấy kết quả nào (thử nghiệm nào trong đó trình duyệt)? Tôi thấy rằng bộ nhớ đệm độ dài luôn luôn là ít nhất là nhanh và thường nhanh hơn. – jfriend00

+0

alright bạn là chính xác ... có vẻ như nó thực sự là một túi hỗn hợp của kết quả tho nhưng bộ nhớ đệm không giúp nó ... nhờ XD – samccone

2

i > 0 nhanh hơn i < arr.length và xảy ra trên mỗi lần lặp của vòng lặp.

Bạn có thể giảm thiểu sự khác biệt với điều này:

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

này vẫn là không nhanh như mục ngược, nhưng nhanh hơn so với tùy chọn phía trước của bạn.

+0

nhìn vào thử nghiệm mã hoá cứng http://jsperf.com/array-iteration-direction ... sử dụng logic của bạn nó sẽ nhanh hơn không? – samccone

5

Nếu bạn muốn có chúng ở cùng một tốc độ, bạn có thể làm điều đó để lặp lại chuyển tiếp;

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

Vì vậy, kịch bản của bạn sẽ không cần phải thực hiện chiều dài của mảng trên everystep.

+0

Ahhh ... thú vị phương pháp của bạn bây giờ mất vương miện cho nhanh nhất iteration http://jsperf.com/array-iteration-direction – samccone

1

Và những đều tốt như nhau:

var arr= [], L= 10000; 
while(L>-1) arr[L]= L--; 

HOẶC

var arr= [], i= 0; 
while(i<10001) arr[i]=i++; 
+0

hahaha tricky tricky – samccone

+0

Nó phải là 'while (- L> = 0) arr [L] = L; ' –

4

Tôi không hoàn toàn chắc chắn về điều này, nhưng ở đây là tôi đoán:

Đối với đoạn mã sau:

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

D uring thời gian chạy, có một tính toán arr.length sau mỗi vòng lặp vượt qua. Đây có thể là một hoạt động tầm thường khi nó đứng một mình, nhưng có thể có tác động khi nói đến nhiều mảng/lớn. bạn có thể thử như sau:

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

Trong đoạn mã trên, ta tính độ dài mảng chỉ một lần, và hoạt động với con số tính toán, chứ không phải thực hiện việc tính toán chiều dài hơn và hơn nữa.

Một lần nữa, chỉ cần đặt suy nghĩ của tôi ở đây. Thú vị quan sát thực sự!

1

thực hiện như dưới đây, nó sẽ hoạt động theo cùng một cách.vì arr.length mất thời gian trong mỗi lần lặp lại trong tương lai.

int len = arr.length; 

mong

for (var i = 0; i < len; ++i) { 
} 

ngược

for (var i = len; i > 0; --i) { 
} 
+0

Trường hợp ngược lại không đúng. Những gì tôi làm là 'cho (i = len; --i> = 0;) {' –

Các vấn đề liên quan