Tôi có mã trông giống như thế này trong javascript:
forloop {
//async call, returns an array to its callback
}
Sau khi tất cả các cuộc gọi async được thực hiện, tôi muốn tính toán min trên tất cả các mảng.
Làm thế nào tôi có thể chờ đợi cho tất cả chúng?
Ý tưởng duy nhất của tôi ngay bây giờ là có một loạt các boolean được gọi là xong, và thiết lập xong [i] thành true trong hàm gọi lại thứ i, sau đó nói trong khi (không phải tất cả được thực hiện) {}
chỉnh sửa: Tôi giả sử một giải pháp có thể, nhưng xấu xí, là chỉnh sửa mảng đã thực hiện trong mỗi cuộc gọi lại, sau đó gọi một phương thức nếu tất cả được thực hiện khác được đặt từ mỗi cuộc gọi lại, do đó cuộc gọi lại cuối cùng sẽ hoàn thành sẽ gọi phương thức tiếp tục.
Cảm ơn trước.
Bạn đã không được rất cụ thể với mã của bạn, vì vậy tôi sẽ tạo nên một kịch bản. Giả sử bạn có 10 cuộc gọi ajax và bạn muốn tích lũy kết quả từ 10 cuộc gọi ajax đó và sau đó khi họ hoàn tất, bạn muốn làm điều gì đó. Bạn có thể làm điều đó như thế này bằng cách tích lũy dữ liệu trong một mảng và theo dõi thời điểm kết thúc dữ liệu cuối cùng:
Bộ đếm thủ công
var ajaxCallsRemaining = 10;
var returnedData = [];
for (var i = 0; i < 10; i++) {
doAjax(whatever, function(response) {
// success handler from the ajax call
// save response
returnedData.push(response);
// see if we're done with the last ajax call
--ajaxCallsRemaining;
if (ajaxCallsRemaining <= 0) {
// all data is here now
// look through the returnedData and do whatever processing
// you want on it right here
}
});
}
Lưu ý: xử lý lỗi rất quan trọng ở đây (không được hiển thị vì nó chỉ rõ cách bạn thực hiện cuộc gọi ajax). Bạn sẽ muốn suy nghĩ về cách bạn sẽ xử lý các trường hợp khi một cuộc gọi ajax không bao giờ hoàn thành, hoặc với một lỗi hoặc bị mắc kẹt trong một thời gian dài hoặc thời gian ra sau một thời gian dài.
jQuery Promises
Thêm vào câu trả lời của tôi trong năm 2014. Những ngày này, lời hứa thường được sử dụng để giải quyết loại vấn đề này kể từ khi jQuery $.ajax()
đã trả lời một lời hứa và $.when()
sẽ cho bạn biết khi một nhóm các lời hứa được giải quyết và sẽ thu thập kết quả trả về cho bạn:
var promises = [];
for (var i = 0; i < 10; i++) {
promises.push($.ajax(...));
}
$.when.apply($, promises).then(function() {
// returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0]
// you can process it here
}, function() {
// error occurred
});
ES6 Standard Promises
Theo quy định trong câu trả lời của kba: nếu bạn có môi trường với lời hứa gốc được tích hợp sẵn (trình duyệt hiện đại hoặc node.js hoặc sử dụng tập tin babeljs transpile hoặc sử dụng lời hứa polyfill), thì bạn có thể sử dụng lời hứa được chỉ định ES6. Xem cái bàn này để hỗ trợ trình duyệt. Lời hứa được hỗ trợ khá nhiều trong tất cả các trình duyệt hiện tại, ngoại trừ IE.
Nếu doAjax()
trả về một lời hứa, sau đó bạn có thể làm điều này:
var promises = [];
for (var i = 0; i < 10; i++) {
promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
// returned data is in arguments[0], arguments[1], ... arguments[n]
// you can process it here
}, function(err) {
// error occurred
});
Nếu bạn cần phải thực hiện một hoạt động không đồng bộ không hứa hẹn thành một hoạt động trả về lời hứa, bạn có thể "quảng cáo" nó như sau:
function doAjax(...) {
return new Promise(function(resolve, reject) {
someAsyncOperation(..., function(err, result) {
if (err) return reject(err);
resolve(result);
});
});
}
Và, sau đó sử dụng mẫu ở trên:
var promises = [];
for (var i = 0; i < 10; i++) {
promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
// returned data is in arguments[0], arguments[1], ... arguments[n]
// you can process it here
}, function(err) {
// error occurred
});
Lời hứa Bluebird
Nếu bạn sử dụng thư viện giàu tính năng hơn, chẳng hạn như Thư viện lời hứa Bluebird, sau đó nó có một số chức năng bổ sung được xây dựng để làm cho điều này dễ dàng hơn:
var doAjax = Promise.promisify(someAsync);
var someData = [...]
Promise.map(someData, doAjax).then(function(results) {
// all ajax results here
}, function(err) {
// some error here
});
Nhận phòng từ năm 2015: Hiện tại chúng tôi có lời hứa gốc trong trình duyệt mới nhất (Cạnh 12, Firefox 40, Chrome 43, Safari 8, Opera 32 và trình duyệt Android 4.4.4 và iOS Safari 8.4, nhưng không phải là Internet Explorer, Opera Mini và các phiên bản cũ hơn của Android).
Nếu chúng tôi muốn thực hiện 10 hành động không đồng bộ và nhận được thông báo khi họ đã hoàn tất, chúng tôi có thể sử dụng Promise.all
, không có bất kỳ thư viện bên ngoài nào:
function asyncAction(i) {
return new Promise(function(resolve, reject) {
var result = calculateResult();
if (result.hasError()) {
return reject(result.error);
}
return resolve(result);
});
}
var promises = [];
for (var i=0; i < 10; i++) {
promises.push(asyncAction(i));
}
Promise.all(promises).then(function AcceptHandler(results) {
handleResults(results),
}, function ErrorHandler(error) {
handleError(error);
});
Bạn có thể sử dụng jQuery Hoãn lại đối tượng cùng với khi nào phương pháp.
deferredArray = [];
forloop {
deferred = new $.Deferred();
ajaxCall(function() {
deferred.resolve();
}
deferredArray.push(deferred);
}
$.when(deferredArray, function() {
//this code is called after all the ajax calls are done
});
Bạn có thể mô phỏng nó như thế này:
countDownLatch = {
count: 0,
check: function() {
this.count--;
if (this.count == 0) this.calculate();
},
calculate: function() {...}
};
thì mỗi cuộc gọi không đồng bộ sẽ thực hiện điều này:
countDownLatch.count++;
trong khi trong mỗi asynch gọi lại ở cuối của phương pháp bạn thêm dòng này:
countDownLatch.check();
Nói cách khác, bạn mô phỏng chức năng đếm ngược.
Đây là cách gọn gàng nhất theo ý kiến của tôi.
Promise.all
FetchAPI
(đối với một số lý do Array.map không hoạt động bên trong .then chức năng cho tôi. Nhưng bạn có thể sử dụng một .forEach và [] .concat () hoặc một cái gì đó tương tự)
Promise.all([
fetch('/user/4'),
fetch('/user/5'),
fetch('/user/6'),
fetch('/user/7'),
fetch('/user/8')
]).then(responses => {
return responses.map(response => {response.json()})
}).then((values) => {
console.log(values);
})
Sử dụng thư viện điều khiển luồng như after
after.map(array, function (value, done) {
// do something async
setTimeout(function () {
// do something with the value
done(null, value * 2)
}, 10)
}, function (err, mappedArray) {
// all done, continue here
console.log(mappedArray)
})