Programing

비동기 콜백 함수 세트를 어떻게 기다릴 수 있습니까?

lottogame 2020. 9. 2. 20:29
반응형

비동기 콜백 함수 세트를 어떻게 기다릴 수 있습니까?


자바 스크립트에서 다음과 같은 코드가 있습니다.

forloop {
    //async call, returns an array to its callback
}

이러한 비동기 호출이 모두 완료된 후 모든 배열에 대한 최소값을 계산하고 싶습니다.

그들 모두를 어떻게 기다릴 수 있습니까?

지금 내 유일한 아이디어는 done이라는 부울 배열을 만들고 ith 콜백 함수에서 done [i]를 true로 설정 한 다음 while (모두 완료되지 않음) {}

편집 : 가능하지만 추악한 해결책은 각 콜백에서 done 배열을 편집 한 다음 각 콜백에서 다른 모든 done이 설정되면 메서드를 호출하는 것이므로 완료 할 마지막 콜백은 계속되는 메서드를 호출합니다.

미리 감사드립니다.


코드에 대해 구체적이지 않았으므로 시나리오를 작성하겠습니다. 10 개의 ajax 호출이 있고 그 10 개의 ajax 호출의 결과를 누적하고 싶은데 모두 완료되면 무언가를하고 싶다고 가정 해 보겠습니다. 배열에 데이터를 축적하고 마지막 항목이 언제 완료되었는지 추적하여 이렇게 할 수 있습니다.

수동 카운터

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
        }
    });
}

참고 : 여기에서 오류 처리가 중요합니다 (Ajax 호출 방법에 따라 다르기 때문에 표시되지 않음). 하나의 ajax 호출이 오류로 인해 완료되지 않거나 오랜 시간 동안 멈춰 있거나 오랜 시간 후에 시간 초과되는 경우를 어떻게 처리 할 것인지 생각하고 싶을 것입니다.


jQuery 약속

2014 년에 제 답변에 추가합니다. 요즘에는 jQuery가 $.ajax()이미 약속을 반환하고 약속 $.when()그룹이 모두 해결되면 알려주고 반환 결과를 수집하기 때문에 이러한 유형의 문제를 해결하는 데 약속이 자주 사용됩니다 .

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 표준 약속

kba의 답변에 명시된대로 : 네이티브 promise가 내장 된 환경 (최신 브라우저 또는 node.js 또는 babeljs transpile 사용 또는 promise polyfill 사용)이있는 경우 ES6 지정 약속을 사용할 수 있습니다. 브라우저 지원 이 표참조하십시오 . 약속은 IE를 제외한 거의 모든 현재 브라우저에서 지원됩니다.

경우 doAjax()약속 반환, 당신은이 작업을 수행 할 수 있습니다

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
});

If you need to make a non-promise async operation into one that returns a promise, you can "promisify" it like this:

function doAjax(...) {
    return new Promise(function(resolve, reject) {
        someAsyncOperation(..., function(err, result) {
            if (err) return reject(err);
            resolve(result);
        });
    });
}

And, then use the pattern above:

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
});

Bluebird Promises

If you use a more feature rich library such as the Bluebird promise library, then it has some additional functions built in to make this easier:

 var doAjax = Promise.promisify(someAsync);
 var someData = [...]
 Promise.map(someData, doAjax).then(function(results) {
     // all ajax results here
 }, function(err) {
     // some error here
 });

Checking in from 2015: We now have native promises in most recent browser (Edge 12, Firefox 40, Chrome 43, Safari 8, Opera 32 and Android browser 4.4.4 and iOS Safari 8.4, but not Internet Explorer, Opera Mini and older versions of Android).

If we want to perform 10 async actions and get notified when they've all finished, we can use the native Promise.all, without any external libraries:

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);
});

You can use jQuery's Deferred object along with the when method.

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
});

You can emulate it like this:

  countDownLatch = {
     count: 0,
     check: function() {
         this.count--;
         if (this.count == 0) this.calculate();
     },
     calculate: function() {...}
  };

then each async call does this:

countDownLatch.count++;

while in each asynch call back at the end of the method you add this line:

countDownLatch.check();

In other words, you emulate a count-down-latch functionality.


This is the most neat way in my opinion.

Promise.all

FetchAPI

(for some reason Array.map doesn't work inside .then functions for me. But you can use a .forEach and [].concat() or something similar)

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);
})

Use an control flow library like 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)
})

참고URL : https://stackoverflow.com/questions/10004112/how-can-i-wait-for-set-of-asynchronous-callback-functions

반응형