각 콜백의 모든 비동기 후 콜백
제목 그대로.이거 어떻게 해?
전화하고 싶다whenAllDone()
forEach-loop이 각 요소를 통과하여 비동기 처리를 수행한 후.
[1, 2, 3].forEach(
function(item, index, array, done) {
asyncFunction(item, function itemDone() {
console.log(item + " done");
done();
});
}, function allDone() {
console.log("All done");
whenAllDone();
}
);
이렇게 작동시킬 수 있을까요?두 번째 인수 for Each가 모든 반복을 거친 후 실행되는 콜백 함수인 경우
예상 출력:
3 done
1 done
2 done
All done!
Array.forEach
에서는, 이러한 세심함을 얻을 수 없습니다(그렇다면).다만, 필요한 것을 실현하기 위한 몇개의 방법이 있습니다.
간이 카운터 사용
function callback () { console.log('all done'); }
var itemsProcessed = 0;
[1, 2, 3].forEach((item, index, array) => {
asyncFunction(item, () => {
itemsProcessed++;
if(itemsProcessed === array.length) {
callback();
}
});
});
(@vanuan 등)이 방법을 사용하면 모든 항목이 "done" 콜백을 호출하기 전에 처리됩니다.콜백으로 갱신되는 카운터를 사용해야 합니다.index 파라미터의 값에 따라서는 비동기 조작의 반환 순서가 보증되지 않기 때문에 동일한 보증이 제공되지 않습니다.
ES6 Promise 사용방법
(이전 브라우저에서는 약속 라이브러리를 사용할 수 있습니다).
동기 실행을 보증하는 모든 요청 처리(예: 1, 2, 3)
function asyncFunction (item, cb) { setTimeout(() => { console.log('done with', item); cb(); }, 100); } let requests = [1, 2, 3].reduce((promiseChain, item) => { return promiseChain.then(() => new Promise((resolve) => { asyncFunction(item, resolve); })); }, Promise.resolve()); requests.then(() => console.log('done'))
"동기" 실행 없이 모든 비동기 요청 처리(2개는 1개보다 더 빨리 완료 가능)
let requests = [1,2,3].map((item) => { return new Promise((resolve) => { asyncFunction(item, resolve); }); }) Promise.all(requests).then(() => console.log('done'));
비동기 라이브러리 사용
그 밖에 비동기 라이브러리가 있습니다.비동기 라이브러리가 가장 인기 있습니다.이 라이브러리는 원하는 것을 표현하는 메커니즘을 제공합니다.
Edit이전에 동기화된 예제를 삭제하도록 질문 본문을 편집했기 때문에 명확하게 하기 위해 답변을 업데이트했습니다.원래의 예에서는, 비동기 동작을 모델화하기 위해서 동기 라이크 코드를 사용하고 있었습니다.따라서 다음 사항이 적용됩니다.
array.forEach
동기화가 되어 있습니다.res.write
따라서 콜 후에 콜백을 전송하기만 하면 됩니다.
posts.foreach(function(v, i) {
res.write(v + ". index " + i);
});
res.end();
비동기 함수가 발생하여 코드를 실행하기 전에 작업을 완료해야 할 경우 언제든지 콜백 기능을 사용할 수 있습니다.
예를 들어 다음과 같습니다.
var ctr = 0;
posts.forEach(function(element, index, array){
asynchronous(function(data){
ctr++;
if (ctr === array.length) {
functionAfterForEach();
}
})
});
주의:functionAfterForEach
Forech 태스크가 종료된 후 실행되는 함수입니다. asynchronous
는 foreach 내에서 실행되는 비동기 함수입니다.
비동기 케이스에 얼마나 많은 오답이 나왔는지 이상하다!인덱스 체크가 예상된 동작을 제공하지 않음을 쉽게 알 수 있습니다.
// INCORRECT
var list = [4000, 2000];
list.forEach(function(l, index) {
console.log(l + ' started ...');
setTimeout(function() {
console.log(index + ': ' + l);
}, l);
});
출력:
4000 started
2000 started
1: 2000
0: 4000
확인하면index === array.length - 1
첫 번째 요소가 보류 중인 동안 첫 번째 반복이 완료되면 콜백이 호출됩니다.
비동기 등의 외부 라이브러리를 사용하지 않고 이 문제를 해결하려면 목록 길이와 반복할 때마다 감소하는 것이 최선이라고 생각합니다.한 가닥의 실이 있기 때문에 레이스 상태가 될 가능성은 없다고 확신하고 있습니다.
var list = [4000, 2000];
var counter = list.length;
list.forEach(function(l, index) {
console.log(l + ' started ...');
setTimeout(function() {
console.log(index + ': ' + l);
counter -= 1;
if ( counter === 0)
// call your callback here
}, l);
});
이것으로 문제가 해결되기를 바랍니다.저는 보통 비동기 태스크를 내부에서 실행할 필요가 있을 때 이 문제를 처리합니다.
foo = [a,b,c,d];
waiting = foo.length;
foo.forEach(function(entry){
doAsynchronousFunction(entry,finish) //call finish after each entry
}
function finish(){
waiting--;
if (waiting==0) {
//do your Job intended to be done after forEach is completed
}
}
와 함께
function doAsynchronousFunction(entry,callback){
//asynchronousjob with entry
callback();
}
ES2018에서는 비동기 반복기를 사용할 수 있습니다.
const asyncFunction = a => fetch(a);
const itemDone = a => console.log(a);
async function example() {
const arrayOfFetchPromises = [1, 2, 3].map(asyncFunction);
for await (const item of arrayOfFetchPromises) {
itemDone(item);
}
console.log('All done');
}
약속 없는 솔루션(모든 액션이 다음 액션이 시작되기 전에 확실하게 종료됩니다)
Array.prototype.forEachAsync = function (callback, end) {
var self = this;
function task(index) {
var x = self[index];
if (index >= self.length) {
end()
}
else {
callback(self[index], index, self, function () {
task(index + 1);
});
}
}
task(0);
};
var i = 0;
var myArray = Array.apply(null, Array(10)).map(function(item) { return i++; });
console.log(JSON.stringify(myArray));
myArray.forEachAsync(function(item, index, arr, next){
setTimeout(function(){
$(".toto").append("<div>item index " + item + " done</div>");
console.log("action " + item + " done");
next();
}, 300);
}, function(){
$(".toto").append("<div>ALL ACTIONS ARE DONE</div>");
console.log("ALL ACTIONS ARE DONE");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="toto">
</div>
이 스레드에서 이를 달성하기 위한 많은 솔루션과 방법이 있습니다.
단, map과 async/wait를 사용하여 이 작업을 수행해야 하는 경우에는 다음과 같습니다.
// Execution Starts
console.log("start")
// The Map will return promises
// the Execution will not go forward until all the promises are resolved.
await Promise.all(
[1, 2, 3].map( async (item) => {
await asyncFunction(item)
})
)
// Will only run after all the items have resolved the asynchronous function.
console.log("End")
출력은 이 정도!비동기 함수에 따라 다를 수 있습니다.
start
2
3
1
end
주의: 맵에서 wait를 사용하면 항상 약속 배열이 반환됩니다.
이것은 비동기 Node.js의 솔루션입니다.
async npm 패키지를 사용합니다.
솔루션:
//Object forEachDone
Object.defineProperty(Array.prototype, "forEachDone", {
enumerable: false,
value: function(task, cb){
var counter = 0;
this.forEach(function(item, index, array){
task(item, index, array);
if(array.length === ++counter){
if(cb) cb();
}
});
}
});
//Array forEachDone
Object.defineProperty(Object.prototype, "forEachDone", {
enumerable: false,
value: function(task, cb){
var obj = this;
var counter = 0;
Object.keys(obj).forEach(function(key, index, array){
task(obj[key], key, obj);
if(array.length === ++counter){
if(cb) cb();
}
});
}
});
예제:
var arr = ['a', 'b', 'c'];
arr.forEachDone(function(item){
console.log(item);
}, function(){
console.log('done');
});
// out: a b c done
Easy Way를 사용하여 문제를 해결하고 공유합니다.
let counter = 0;
arr.forEach(async (item, index) => {
await request.query(item, (err, recordset) => {
if (err) console.log(err);
//do Somthings
counter++;
if(counter == tableCmd.length){
sql.close();
callback();
}
});
request
mssql은 mssql로 지정됩니다.이것은 원하는 각 기능 또는 코드를 대체할 수 있습니다.
var i=0;
const waitFor = (ms) =>
{
new Promise((r) =>
{
setTimeout(function () {
console.log('timeout completed: ',ms,' : ',i);
i++;
if(i==data.length){
console.log('Done')
}
}, ms);
})
}
var data=[1000, 200, 500];
data.forEach((num) => {
waitFor(num)
})
var counter = 0;
var listArray = [0, 1, 2, 3, 4];
function callBack() {
if (listArray.length === counter) {
console.log('All Done')
}
};
listArray.forEach(function(element){
console.log(element);
counter = counter + 1;
callBack();
});
세트는 어때?전체 반복 횟수를 확인하는 간격은 보증을 가져옵니다.스코프에 과부하가 걸리지 않을지는 모르겠지만, 저는 그것을 사용하고 있습니다.
_.forEach(actual_JSON, function (key, value) {
// run any action and push with each iteration
array.push(response.id)
});
setInterval(function(){
if(array.length > 300) {
callback()
}
}, 100);
목록을 반복하기 위해 콜백이 필요하지 않습니다. ㅇㅇㅇㅇㅇㅇㅇ를 돼요.end()
루프를 호출합니다.
posts.forEach(function(v, i){
res.write(v + ". Index " + i);
});
res.end();
언급URL : https://stackoverflow.com/questions/18983138/callback-after-all-asynchronous-foreach-callbacks-are-completed
'programing' 카테고리의 다른 글
JavaScript에서 setInterval 호출 중지 (0) | 2022.10.19 |
---|---|
node.js를 사용하여 mySQL에 대량 삽입하려면 어떻게 해야 합니까? (0) | 2022.10.19 |
새 폴더 작성 방법 (0) | 2022.10.19 |
JavaScript는 붙여넣기 이벤트에서 클립보드 데이터를 가져옵니다(크로스 브라우저). (0) | 2022.10.19 |
Java I/O에서 "Stream"과 "Buffer"는 정확히 무엇을 의미합니까? (0) | 2022.10.19 |