2011-12-07 31 views
31

Đó là cách tôi thực hiện:Whats cách thông minh nhất/sạch nhất để lặp lại async qua mảng (hoặc objs) là gì?

function processArray(array, index, callback) { 
    processItem(array[index], function(){ 
     if(++index === array.length) { 
      callback(); 
      return; 
     } 
     processArray(array, index, callback); 
    }); 
}; 

function processItem(item, callback) { 
    // do some ajax (browser) or request (node) stuff here 

    // when done 
    callback(); 
} 

var arr = ["url1", "url2", "url3"]; 

processArray(arr, 0, function(){ 
    console.log("done"); 
}); 

Có tốt không? Làm thế nào để tránh những mã spaghetti'ish?

+0

Với jQuery, bạn có thể sử dụng '$ .each ([...], function() {...});' và sẽ có các phương thức tương tự trong các thư viện JS khác. –

+12

Có, nhưng chúng là đồng bộ. Aron hỏi về các vòng không đồng bộ, một vấn đề thú vị hơn nhiều! –

+0

năm 2016 và tôi đã sử dụng ngày hôm nay. Có lẽ nên nhìn vào ES6 nhưng ... cảm ơn! – Squidinker

Trả lời

30

Thanh toán thư viện async, nó được tạo cho luồng điều khiển (công cụ không đồng bộ) và nó có rất nhiều phương pháp cho mảng công cụ: mỗi bộ lọc, bản đồ. Kiểm tra tài liệu trên github. Đây là những gì bạn có thể cần:

mỗi (arr, iterator, callback)

Áp dụng một chức năng lặp cho mỗi mục trong một mảng, song song. Trình lặp được gọi với một mục từ danh sách và một cuộc gọi lại khi nó đã kết thúc. Nếu trình vòng lặp chuyển một lỗi tới cuộc gọi lại này, cuộc gọi lại chính cho hàm each ngay lập tức được gọi với lỗi.

eachSeries (arr, iterator, callback)

Giống như each chỉ iterator được áp dụng cho từng hạng mục trong mảng trong loạt. Trình lặp tiếp theo chỉ được gọi khi trình xử lý hiện tại đã hoàn tất quá trình xử lý. Điều này có nghĩa là các hàm lặp sẽ hoàn thành theo thứ tự.

+0

Có, async.js rất tiện dụng! –

+0

các chức năng được gọi là "mỗi" và "eachSeries" https://github.com/caolan/async#each –

+0

Hãy nhớ rằng nhận xét của ông đã được viết hai năm trước khi bạn mặc dù @LaurentDebricon – NicT

9

Như một cách chính xác chỉ ra, bạn phải sử dụng setTimeout, ví dụ:

each_async = function(ary, fn) { 
    var i = 0; 
    -function() { 
     fn(ary[i]); 
     if (++i < ary.length) 
      setTimeout(arguments.callee, 0) 
    }() 
} 


each_async([1,2,3,4], function(p) { console.log(p) }) 
+3

@downvoter: có vấn đề gì với điều này? – georg

+8

Tại sao có dấu "-" (trừ) trước hàm 'thứ hai()' thứ hai? –

+5

@AaronDigulla '-function()' làm cho hàm ngay lập tức được coi là một biểu thức. Nó không thực sự khác với việc gói hàm trong ngoặc đơn, đó là một cách khác để làm cho nó trở thành một biểu thức hợp lệ. xem: http://stackoverflow.com/questions/13341698/javascript-plus-sign-in-front-of-function-name –

17

Như đã chỉ trong một số câu trả lời người ta có thể sử dụng "async" thư viện. Nhưng đôi khi bạn không muốn giới thiệu sự phụ thuộc mới vào mã của bạn. Và dưới đây là một cách khác như thế nào bạn có thể lặp lại và chờ đợi để hoàn thành một số chức năng không đồng bộ.

var items = ["one", "two", "three"]; 

// This is your async function, which may perform call to your database or 
// whatever... 
function someAsyncFunc(arg, cb) { 
    setTimeout(function() { 
     cb(arg.toUpperCase()); 
    }, 3000); 
} 

// cb will be called when each item from arr has been processed and all 
// results are available. 
function eachAsync(arr, func, cb) { 
    var doneCounter = 0, 
     results = []; 
    arr.forEach(function (item) { 
     func(item, function (res) { 
      doneCounter += 1; 
      results.push(res); 
      if (doneCounter === arr.length) { 
       cb(results); 
      } 
     }); 
    }); 
} 

eachAsync(items, someAsyncFunc, console.log); 

Bây giờ, chạy node iterasync.js sẽ chờ khoảng ba giây và sau đó in [ 'ONE', 'TWO', 'THREE' ]. Đây là một ví dụ đơn giản, nhưng nó có thể được mở rộng để xử lý nhiều tình huống.

+3

Thật đáng kinh ngạc là câu trả lời này không có ý nghĩa thống kê ở mức bình luận này. – Gepser

+0

Giải pháp tuyệt vời! – nebulus

+1

Đầu ra có thể không nhất thiết phải ở mức 1,2,3. – fuermosi777

2

Cách dễ nhất để xử lý lặp lại không đồng bộ của mảng (hoặc bất kỳ lần lặp nào khác) là với toán tử chờ (chỉ trong các hàm không đồng bộ) và cho vòng lặp.

(async function() { 
 
for(let value of [ 0, 1 ]) { 
 
    value += await(Promise.resolve(1)) 
 
    console.log(value) 
 
} 
 
})()

Bạn có thể sử dụng một thư viện để chuyển đổi bất kỳ chức năng bạn có thể cần mà chấp nhận callback để trở lại hứa hẹn.

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