2011-10-13 40 views
24

Tôi đang cố gắng chạy nhiều bộ tính giờ cho một danh sách các mục thay đổi. Mã trông giống như sau:Cách sử dụng chức năng setInterval trong vòng lặp

var list = Array(...); 

for(var x in list){ 
    setInterval(function(){ 
     list[x] += 10; 
     console.log(x + "=>" + list[x] + "\n"); 
    }, 5 * 1000); 
} 

Vấn đề với mã ở trên là giá trị duy nhất được cập nhật là mục ở cuối danh sách, nhân với số mục trong danh sách.

Có ai có thể đưa ra giải pháp và một số giải thích để tôi biết tại sao nó hoạt động theo cách này không?

Trả lời

32

Vì vậy, một vài điều:

  1. Quan trọng nhất là chức năng gọi lại bạn đã vượt qua để setInterval() duy trì một tham chiếu đến x chứ không phải là giá trị bản chụp của x vì nó tồn tại trong mỗi lần lặp cụ thể. Vì vậy, vì x được thay đổi trong vòng lặp, nó được cập nhật trong mỗi chức năng gọi lại.
  2. Ngoài ra, for...in được sử dụng để liệt kê các thuộc tính đối tượng và có thể behave unexpectedly khi được sử dụng trên các mảng.
  3. Hơn nữa, tôi nghi ngờ bạn thực sự muốn setTimeout() thay vì setInterval().

Bạn có thể vượt qua đối số cho hàm callback của bạn bằng cách cung cấp luận cứ bổ sung cho setTimout():

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

Dưới đây là một ví dụ:

var list = [1,2,3,4]; 
 

 
for (var x = 0, ln = list.length; x < ln; x++) { 
 
    setTimeout(function(y) {  
 
    console.log("%d => %d", y, list[y] += 10); 
 
    }, x * 500, x); // we're passing x 
 
}

May mắn thay, số được thông qua theo giá trị thay vì tham chiếu.

+0

Có, tôi có thể khuyên bạn nên đọc bài viết này: http://blog.morrisjohns.com/javascript_closures_for_dummies. Trên hết, mặc dù setTimeout trong vòng lặp có thể không phải là những gì anh ta muốn làm dù sao tất cả các cuộc gọi lại sẽ được kích hoạt cùng một lúc, họ sẽ không bị so le. – SoWeLie

+0

OP không "cần đóng cửa", hoàn toàn ngược lại - nó có một đóng cửa để * x * mà cần phải tránh (mà câu trả lời của bạn thực sự không). Nó giữ đóng cửa * danh sách * mặc dù. – RobG

33

Đây là mã làm việc:

var list = [1, 2, 3, 4, 5]; 

for (var i = 0, len = list.length; i < len; i += 1) { 
    (function(i) { 
     setInterval(function() { 
      list[i] += 10; 
      console.log(i + "=>" + list[i] + "\n"); 
     }, 5000) 
    })(i); 
} 

Đây chỉ số i được lưu trữ trong một chức năng ẩn danh, do đó nó không được ghi đè bởi các vòng liên tiếp. Chức năng setInterval trong mã của bạn chỉ giữ tham chiếu đến giá trị cuối cùng của i.

+0

giải pháp tốt !! –

+0

Giải pháp tuyệt vời! Một lưu ý nhỏ: bất cứ điều gì có thể được thay đổi trong vòng lặp có thể được chuyển đến hàm ẩn danh, không chỉ là chỉ mục. –

2

Bạn không phải sử dụng chu trình cho câu hỏi setInterval. Hãy thử điều này:

var list = Array(...); 
var x = 0; 

setInterval(function() { 

    if (x < list.length;) { 
     list[x] += 10; 
     console.log(x+"=>"+list[x]); 
    } 

    else return; 

    x++; 
}, 5000); 
0

Nếu bạn có mảng JSON và jQuery bao gồm, bạn có thể sử dụng:

$.each(jsonArray, function(i, obj) { 
    setInterval(function() { 
     console.log(i+' '+obj); 
    }, 10); 
}); 
2

Tôi không biết làm thế nào để làm điều này với một vòng lặp for nhưng mã này ở đây sẽ in ra mỗi phần tử trong một mảng tại các khoảng thời gian định sẵn:

function displayText(str) { 
    $('.demo').append($('<div>').text(str)); 
} 
var i = 0; 

var a = [12, 3, 45, 6, 7, 10]; 

function timedLoop() { 
setTimeout(function() { 
    displayText(a[i]); 
    i++; 
    if(i < a.length) { 
     timedLoop(); 
    } 
}, 2000) 
} 

timedLoop(); 

Sử dụng một chút jquery để hiển thị trong trình duyệt.

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