여러 아약스 호출에 대한 jQuery 콜백


132

클릭 이벤트에서 3 개의 아약스 호출을하고 싶습니다. 각 아약스 호출은 고유 한 작업을 수행하고 최종 콜백에 필요한 데이터를 반환합니다. 전화 자체는 서로 의존하지 않으며 모두 동시에 갈 수 있지만 세 가지가 모두 완료되면 최종 콜백을하고 싶습니다.

$('#button').click(function() {
    fun1();
    fun2();
    fun3();
//now do something else when the requests have done their 'success' callbacks.
});

var fun1= (function() {
    $.ajax({/*code*/});
});
var fun2 = (function() {
    $.ajax({/*code*/});
});
var fun3 = (function() {
    $.ajax({/*code*/});
});


답변:


112

여기에 내가 작성한 콜백 객체가 있습니다. 한 번의 콜백이 모두 완료되면 발생하거나 각각 고유의 콜백이 있고 모두 완료되면 모두 호출하도록 설정할 수 있습니다.

주의

jQuery 1.5 이상부터 다른 답변에 설명 된대로 지연된 메소드를 사용할 수 있습니다.

  $.when($.ajax(), [...]).then(function(results){},[...]);

여기서 연기되는 예

jQuery <1.5의 경우 다음이 작동하거나 두 개의 버튼으로 여기에 표시된 것처럼 알 수없는 시간에 ajax 호출을 시작 해야하는 경우 : 두 버튼을 클릭 한 후 시작

[용법]

에 대한 하나의 완전한 번 콜백 : 작업 예

// initialize here
var requestCallback = new MyRequestsCompleted({
    numRequest: 3,
    singleCallback: function(){
        alert( "I'm the callback");
    }
});

//usage in request
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.requestComplete(true);
    }
});

모두 완료되면 각각 자체 콜백이 발생합니다. 작업 예

//initialize 
var requestCallback = new MyRequestsCompleted({
    numRequest: 3
});

//usage in request
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the first callback');
        });
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the second callback');
        });
    }
});
$.ajax({
    url: '/echo/html/',
    success: function(data) {
        requestCallback.addCallbackToQueue(true, function() {
            alert('Im the third callback');
        });
    }
});

[코드]

var MyRequestsCompleted = (function() {
    var numRequestToComplete, requestsCompleted, callBacks, singleCallBack;

    return function(options) {
        if (!options) options = {};

        numRequestToComplete = options.numRequest || 0;
        requestsCompleted = options.requestsCompleted || 0;
        callBacks = [];
        var fireCallbacks = function() {
            alert("we're all complete");
            for (var i = 0; i < callBacks.length; i++) callBacks[i]();
        };
        if (options.singleCallback) callBacks.push(options.singleCallback);

        this.addCallbackToQueue = function(isComplete, callback) {
            if (isComplete) requestsCompleted++;
            if (callback) callBacks.push(callback);
            if (requestsCompleted == numRequestToComplete) fireCallbacks();
        };
        this.requestComplete = function(isComplete) {
            if (isComplete) requestsCompleted++;
            if (requestsCompleted == numRequestToComplete) fireCallbacks();
        };
        this.setCallback = function(callback) {
            callBacks.push(callBack);
        };
    };
})();

1
훌륭한 코드 예제에 감사드립니다! 나는 나머지를 통해 내 길을 우연히 발견 할 수 있다고 생각합니다. 다시 감사합니다!
MisterIsaak

문제 없음, 도움이 되었기 때문입니다! 나는 그것을 가지고 갔다 : P는 여전히 그것에 대한 아이디어가 더있다. 초기화시 많은 요청을 지정할 필요가없는 곳으로 업데이트 할 계획입니다.
subhaze

좋아, 나는 당신이하기를 바랍니다! 매우 흥미로운 것은 추가 콜백을 추가하는 옵션을 던지는 것이 좋습니다. 나는하고 내가하고 싶은 일에 완벽하게 작동합니다. 다시 감사합니다!
MisterIsaak

나는 그것을 사용 사례에 추가하는 것을 잊었다. : P setCallback는 대기열에 더 많은 것을 추가하는 데 사용 한다. 지금은 그것에 대해 생각하지만 ... 나는 그것을 호출해야 addCallback이 큐에 추가 년대 이후 또는 종류의 뭔가를 ... 그냥 설정하지
subhaze

singleCallback두 번째 줄 의 변수가 불필요합니까? 아니면 뭔가 빠졌습니까?
nimcap

158

이것에 대한 답변이있는 것처럼 보이지만 여기에 언급 할 가치가있어 코드를 크게 단순화 할 수 있다고 생각합니다. jQuery는 $.whenv1.5에서 도입되었습니다 . 다음과 같습니다.

$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
    //this callback will be fired once all ajax calls have finished.
});

여기에 언급되지 않은 것이 도움이 되길 바랍니다.


6
답변 주셔서 감사합니다, 이것은 확실히 나에게 갈 길입니다. jQuery를 사용하며 작고 짧으며 표현력이 뛰어납니다.
nimcap

2
Subhaze의 ​​답변은 훌륭하지만 실제로는 이것이 맞습니다.
몰 롬비

9
jQuery 1.5 이상을 사용하는 경우 이것이 좋은 솔루션이지만 동의 시점에 지연된 기능을 사용할 수 없다는 데 동의합니다. :(
subhaze

13

어떤 물체에 대한 필요성도 알지 못합니다. 단순은 정수인 변수를 갖습니다. 요청을 시작할 때 숫자를 늘리십시오. 완료되면 줄이십시오. 값이 0이면 진행중인 요청이 없으므로 완료된 것입니다.

$('#button').click(function() {
    var inProgress = 0;

    function handleBefore() {
        inProgress++;
    };

    function handleComplete() {
        if (!--inProgress) {
            // do what's in here when all requests have completed.
        }
    };

    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
    $.ajax({
        beforeSend: handleBefore,
        complete: function () {
            // whatever
            handleComplete();
            // whatever
        }
    });
});

이것은 매우 간단하고 완벽하게 작동합니다 ... if (--progress)에서 어떤 일이 발생하는지 조금 더 설명해 주시겠습니까? 변수 inProgress == 0인지 제어하고 한 단위를 빼야하지만 간단한 구문을 얻지 못합니다 ...
Pitto

1
@Pitto : 죄송합니다. 실제로 논리 오류가 있으며이어야합니다 if (!--inProgress). 올바른 버전은와 유사합니다 inProgress = inProgress - 1; if (inProgress == 0) { /* do stuff */ }. 컴팩트 한 형태는 결합 프리픽스 감소 연산자 ( --) 및 부정 연산자 ( !) "참"으로 평가하는 (따라서 실행 if블록)를 감소시키는 경우 inProgress에 결과 inProgress == 0달리 "FALSE"로하고, 평가합니다 (그리고 따라서 행하는 것이다 아무것도).
Matt

간단하게 시간과 인내심에 감사드립니다.
Pitto

@Pitto : Humm .. 사용중인 코드에 연결할 수 있습니까? 그것은 나를 위해 작동합니다 .
Matt

10

주목할 그것은의 가치가 그 이후 $.when모든 순차적 인수로 아약스 요청 (안 배열)를 흔히 볼 수 있습니다에게 기대 $.when와 함께 사용 .apply()과 같이 :

// Save all requests in an array of jqXHR objects
var requests = arrayOfThings.map(function(thing) {
    return $.ajax({
        method: 'GET',
        url: 'thing/' + thing.id
    });
});
$.when.apply(this, requests).then(function(resp1, resp2/*, ... */) {
    // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
    var responseArgsArray = Array.prototype.slice.call(this, arguments);

});

이것은 이와 $.when같은 인수를 허용 하기 때문입니다

$.when(ajaxRequest1, ajaxRequest2, ajaxRequest3);

그리고 이것처럼 :

$.when([ajaxRequest1, ajaxRequest2, ajaxRequest3]);

훌륭한 반응. 현재 좋은 약속 라이브러리가 많이 있습니다. 대부분의 all메소드 또는 비슷한 것이 있지만지도 개념이 마음에 듭니다. 좋은.
Greg

2
예, 거의 항상 $ .w를 사용하여 배열에 요청을 적용하고 여기에서 해결책을 찾지 못했기 때문에 여기에 좋은 예가되도록 추가했습니다.
Cory Danielson

4

나는 hvgotcodes의 아이디어를 좋아합니다. 내 제안은 완료 수를 필요한 수와 비교 한 다음 최종 콜백을 실행하는 일반 증분기를 추가하는 것입니다. 이것은 최종 콜백에 내장 될 수 있습니다.

var sync = {
 callbacksToComplete = 3,
 callbacksCompleted = 0,
 addCallbackInstance = function(){
  this.callbacksCompleted++;
  if(callbacksCompleted == callbacksToComplete) {
   doFinalCallBack();
  }
 }
};

[이름 업데이트를 반영하도록 편집되었습니다.]


^ 동의, 내가 실제로 필요한 것을 더 잘 이해하도록 도왔습니다.
MisterIsaak

3

편집-아마도 가장 좋은 옵션은 세 가지 요청이하는 모든 작업을 수행하는 서비스 엔드 포인트를 만드는 것입니다. 그렇게하면 하나의 요청 만하면됩니다. 모든 데이터는 응답에 필요한 곳입니다. 동일한 3 번의 요청을 반복해서 반복하는 경우이 경로를 사용하고 싶을 것입니다. 일반적으로 작은 서버 작업을 함께 사용하는 서버에 파사드 서비스를 설정하는 것이 좋은 설계 결정입니다. 그냥 생각이야


이를 수행하는 한 가지 방법은 ajax 호출 전에 클릭 핸들러에서 '동기화'객체를 만드는 것입니다. 같은 것

var sync = {
   count: 0
}

동기화는 성공 호출 범위에 자동으로 연결됩니다 (폐쇄). 성공 처리기에서는 개수를 늘리고 3이면 다른 함수를 호출 할 수 있습니다.

또는, 당신은 같은 것을 할 수 있습니다

var sync = {
   success1Complete: false,
   ...
   success3Complete: false,
}

성공할 때마다 동기화의 값이 true로 변경됩니다. 계속하기 전에 동기화를 확인하여 세 가지가 모두 맞는지 확인해야합니다.

xhr 중 하나가 성공을 반환하지 않는 경우를 고려해야합니다.

또 다른 옵션은 항상 성공 처리기에서 최종 함수를 호출하고 sync 옵션에 액세스하여 실제로 어떤 작업을 수행할지 여부를 결정하는 것입니다. 그래도 동기화가 해당 기능의 범위 내에 있는지 확인해야합니다.


몇 가지 이유로 첫 제안을 더 좋아합니다. 각 요청에는 고유 한 목적이 있으므로 그 이유로 별도 요청을 유지하고 싶습니다. 또한 요청은 다른 곳에서 사용하기 때문에 실제로 함수에 있으므로 가능한 경우 모듈 식 디자인을 유지하려고했습니다. 당신의 도움을 주셔서 감사합니다!
MisterIsaak

@Jisaak, 그렇습니다.이 문제를 처리하기 위해 서버에 메소드를 넣는 것은 당신에게 적합하지 않을 수 있습니다. 그러나 서버에 파사드를 설정하는 것은 허용됩니다. 모듈성에 대해 이야기하면서 세 가지를 모두 처리하는 하나의 방법을 만드는 것은 모듈 식입니다.
hvgotcodes


0

이 페이지의 답변에서 좋은 힌트를 얻었습니다. 나는 그것을 내 용도에 맞게 조금 수정하고 공유 할 수 있다고 생각했습니다.

// lets say we have 2 ajax functions that needs to be "synchronized". 
// In other words, we want to know when both are completed.
function foo1(callback) {
    $.ajax({
        url: '/echo/html/',
        success: function(data) {
            alert('foo1');
            callback();               
        }
    });
}

function foo2(callback) {
    $.ajax({
        url: '/echo/html/',
        success: function(data) {
            alert('foo2');
            callback();
        }
    });
}

// here is my simplified solution
ajaxSynchronizer = function() {
    var funcs = [];
    var funcsCompleted = 0;
    var callback;

    this.add = function(f) {
        funcs.push(f);
    }

    this.synchronizer = function() {
        funcsCompleted++;
        if (funcsCompleted == funcs.length) {
            callback.call(this);
        }
    }

    this.callWhenFinished = function(cb) {
        callback = cb;
        for (var i = 0; i < funcs.length; i++) {
            funcs[i].call(this, this.synchronizer);
        }
    }
}

// this is the function that is called when both ajax calls are completed.
afterFunction = function() {
    alert('All done!');
}

// this is how you set it up
var synchronizer = new ajaxSynchronizer();
synchronizer.add(foo1);
synchronizer.add(foo2);
synchronizer.callWhenFinished(afterFunction);

여기에는 몇 가지 제한 사항이 있지만 제 경우에는 문제가 없었습니다. 또한 고급 기능을 위해 유용한 AOP 플러그인 (jQuery 용)이 있음을 발견했습니다. http://code.google.com/p/jquery-aop/


0

나는 오늘이 문제를 겪었고 허용 된 답변을보기 전에 내 순진한 시도였습니다.

<script>
    function main() {
        var a, b, c
        var one = function() {
            if ( a != undefined  && b != undefined && c != undefined ) {
                alert("Ok")
            } else {
                alert( "¬¬ ")
            }
        }

        fakeAjaxCall( function() {
            a = "two"
            one()
        } )
        fakeAjaxCall( function() {
            b = "three"
            one()
        } )
        fakeAjaxCall( function() {
            c = "four"
            one()
        } )
    }
    function fakeAjaxCall( a ) {
        a()
    }
    main()
</script>

0

jquery가 아니며 (jquery에 실행 가능한 솔루션이있는 것처럼 보임) 다른 옵션과 같습니다.

SharePoint 웹 서비스에서 많은 작업을 수행하는 데 비슷한 문제가 발생했습니다. 단일 프로세스에 대한 입력을 생성하기 위해 여러 소스에서 데이터를 가져와야하는 경우가 종종 있습니다.

이를 해결하기 위해 이런 종류의 기능을 AJAX 추상화 라이브러리에 포함 시켰습니다. 완료되면 일련의 핸들러를 트리거하는 요청을 쉽게 정의 할 수 있습니다. 그러나 각 요청은 여러 http 호출로 정의 될 수 있습니다. 구성 요소 및 자세한 설명서는 다음과 같습니다.

DepressedPress.com의 DPAJAX

이 간단한 예제는 세 번의 호출로 하나의 요청을 작성한 다음 해당 정보를 호출 순서로 단일 핸들러로 전달합니다.

    // The handler function 
function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) }; 

    // Create the pool 
myPool = DP_AJAX.createPool(); 

    // Create the request 
myRequest = DP_AJAX.createRequest(AddUp); 

    // Add the calls to the request 
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]); 
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]); 
myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]); 

    // Add the request to the pool 
myPool.addRequest(myRequest); 

다른 많은 솔루션과 달리 (jquery의 "언제"솔루션을 포함하여)이 방법으로 호출의 단일 스레딩을 강요하지 않는 경우 각 환경은 환경이 허용하는 한 빨리 (또는 느리게) 실행됩니다. 그러나 단일 핸들러는 모두 완료된 경우에만 호출됩니다. 또한 시간 초과 값 설정을 지원하고 서비스가 약간 잘못된 경우 재 시도를 시도합니다.

나는 그것이 매우 유용하다는 것을 알았습니다 (코드 관점에서 이해하는 것은 매우 간단합니다). 더 이상 체인 연결, 더 이상 통화 계산 및 출력 저장이 없습니다. 그냥 "설정하고 잊어 버리세요".


0

좋아, 이것은 오래되었지만 내 솔루션에 기여하도록하십시오 :)

function sync( callback ){
    syncCount--;
    if ( syncCount < 1 ) callback();
}
function allFinished(){ .............. }

window.syncCount = 2;

$.ajax({
    url: 'url',
    success: function(data) {
        sync( allFinished );
    }
});
someFunctionWithCallback( function(){ sync( allFinished ); } )

콜백이있는 함수에서도 작동합니다. syncCount를 설정하고 모든 작업의 ​​콜백에서 sync (...) 함수를 호출합니다.


0

대기열을 정렬하는 추가 방법이 없어도 더 쉬운 방법을 찾았습니다.

JS

$.ajax({
  type: 'POST',
  url: 'ajax1.php',
  data:{
    id: 1,
    cb:'method1'//declaration of callback method of ajax1.php
  },
  success: function(data){
  //catching up values
  var data = JSON.parse(data);
  var cb=data[0].cb;//here whe catching up the callback 'method1'
  eval(cb+"(JSON.stringify(data));");//here we calling method1 and pass all data
  }
});


$.ajax({
  type: 'POST',
  url: 'ajax2.php',
  data:{
    id: 2,
    cb:'method2'//declaration of callback method of ajax2.php
  },
  success: function(data){
  //catching up values
  var data = JSON.parse(data);
  var cb=data[0].cb;//here whe catching up the callback 'method2'
  eval(cb+"(JSON.stringify(data));");//here we calling method2 and pass all data
  }
});


//the callback methods
function method1(data){
//here we have our data from ajax1.php
alert("method1 called with data="+data);
//doing stuff we would only do in method1
//..
}

function method2(data){
//here we have our data from ajax2.php
alert("method2 called with data="+data);
//doing stuff we would only do in method2
//..
}

PHP (ajax1.php)

<?php
    //catch up callbackmethod
    $cb=$_POST['cb'];//is 'method1'

    $json[] = array(
    "cb" => $cb,
    "value" => "ajax1"
    );      

    //encoding array in JSON format
    echo json_encode($json);
?>

PHP (ajax2.php)

<?php
    //catch up callbackmethod
    $cb=$_POST['cb'];//is 'method2'

    $json[] = array(
    "cb" => $cb,
    "value" => "ajax2"
    );      

    //encoding array in JSON format
    echo json_encode($json);
?>

-1
async   : false,

기본적으로 모든 요청은 비동기 적으로 전송됩니다 (즉, 기본적으로 true로 설정 됨). 동기 요청이 필요한 경우이 옵션을로 설정하십시오 false. 도메인 간 요청 및 dataType: "jsonp"요청은 동기 작업을 지원하지 않습니다. 동기 요청은 브라우저를 일시적으로 잠글 수 있으며 요청이 활성화 된 동안 모든 작업을 비활성화 할 수 있습니다. 현재 jQuery를 1.8 의 사용 async: falsejqXHR는 ( $.Deferred)는 지원되지 않습니다; 당신은 사용해야 성공 / 오류 / 전체 의 대응 방법 대신 콜백 옵션을 jqXHR의 같은 객체 jqXHR.done()또는 사용되지 않는 jqXHR.success().


이것은 적절한 해결책이 아닙니다. 동기식 Ajax 요청을해서는 안됩니다.
user128216

-2
$.ajax({type:'POST', url:'www.naver.com', dataType:'text', async:false,
    complete:function(xhr, textStatus){},
    error:function(xhr, textStatus){},
    success:function( data ){
        $.ajax({type:'POST', 
            ....
            ....
            success:function(data){
                $.ajax({type:'POST',
                    ....
                    ....
            }
        }
    });

미안하지만 내가 무엇을 욕설하는지 설명 할 수 없다 나는 영어로 단어를 말할 수없는 한국인입니다. 그러나 나는 당신이 그것을 쉽게 이해할 수 있다고 생각합니다.


이 방법으로 아약스를 사용해서는 안됩니다. 콜백 지옥 ..!
traeper
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.