Vòng lặp for
chạy ngay lập tức để hoàn tất trong khi tất cả các hoạt động không đồng bộ của bạn được bắt đầu. Khi họ hoàn thành một số thời gian trong tương lai và gọi callbacks của họ, giá trị của biến chỉ số vòng lặp của bạn i
sẽ có giá trị cuối cùng cho tất cả các cuộc gọi lại.
Điều này là do vòng lặp for
không chờ một thao tác không đồng bộ hoàn thành trước khi tiếp tục lặp lại tiếp theo của vòng lặp và do cuộc gọi lại không đồng bộ được gọi là thời gian trong tương lai. Do đó, vòng lặp hoàn thành các lần lặp của nó và THEN các callback được gọi khi các hoạt động async đó kết thúc. Như vậy, chỉ số vòng lặp là "thực hiện" và ngồi ở giá trị cuối cùng của nó cho tất cả các cuộc gọi lại.
Để giải quyết vấn đề này, bạn phải lưu duy nhất chỉ mục vòng lặp riêng cho từng cuộc gọi lại. Trong Javascript, cách để làm điều đó là bắt giữ nó trong một hàm đóng. Điều đó có thể được thực hiện bằng cách tạo một hàm đóng nội dòng đặc biệt cho mục đích này (ví dụ đầu tiên được hiển thị bên dưới) hoặc bạn có thể tạo một hàm bên ngoài mà bạn chuyển chỉ mục đến và duy trì chỉ mục duy nhất cho bạn (ví dụ thứ hai được hiển thị bên dưới).
Tính đến năm 2016, nếu bạn có một để-spec lên đầy đủ ES6 thi hành Javascript, bạn cũng có thể sử dụng let
để xác định các biến for
vòng lặp và nó sẽ được xác định duy nhất cho mỗi lần lặp của for
vòng lặp (thi thứ ba phía dưới). Nhưng, lưu ý đây là một tính năng triển khai muộn trong việc triển khai ES6, do đó bạn phải đảm bảo rằng môi trường thực thi của bạn hỗ trợ tùy chọn đó.
Sử dụng.foreach() để lặp vì nó tạo ra chức năng đóng cửa riêng của mình
someArray.forEach(function(item, i) {
asynchronousProcess(function(item) {
console.log(i);
});
});
Tạo riêng cho chức năng Đóng cửa của bạn sử dụng một IIFE
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asynchronousProcess(function() {
console.log(cntr);
});
})(i);
}
Tạo hoặc Modify Chức năng bên ngoài và Vượt qua nó Biến
Nếu bạn có thể sửa đổi chức năng asynchronousProcess()
, thì bạn chỉ có thể chuyển giá trị trong đó và có asynchronousProcess()
hoạt các CNTR lại gọi lại như thế này:
var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}
Sử dụng ES6 let
Nếu bạn có một môi trường thực thi Javascript hỗ trợ đầy đủ ES6, bạn có thể sử dụng let
trong vòng lặp for
của bạn như thế này:
const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
let
khai báo trong một tuyên bố for
vòng lặp như thế này sẽ tạo ra một uni giá trị que của i
cho mỗi lần gọi vòng lặp (đó là những gì bạn muốn).
Serializing với lời hứa và async/chờ đợi
Nếu chức năng async của bạn trả về một lời hứa, và bạn muốn serialize hoạt động async của bạn để chạy cái khác thay vì song song và bạn đang chạy trong một hiện đại môi trường hỗ trợ async
và await
, sau đó bạn có nhiều tùy chọn hơn.
async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
này sẽ đảm bảo rằng chỉ có một cuộc gọi đến asynchronousProcess()
đang bay tại một thời điểm và for
loop thậm chí sẽ không thúc đẩy cho đến khi mỗi người được thực hiện. Điều này khác với các lược đồ trước đó mà tất cả chạy các hoạt động không đồng bộ của bạn song song nên nó phụ thuộc hoàn toàn vào thiết kế mà bạn muốn. Lưu ý: await
hoạt động với lời hứa để chức năng của bạn phải trả lại lời hứa được giải quyết/bị từ chối khi thao tác không đồng bộ hoàn tất. Ngoài ra, lưu ý rằng để sử dụng await
, hàm chứa phải được khai báo async
.
Cách thêm tham số i vào hàm 'asynchronousProcess'? Mà có thể vượt qua nó trên để callbackFunction –
có thể trùng lặp của [Javascript đóng cửa bên trong vòng - ví dụ đơn giản thực tế] (http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) –