2014-12-30 1 views
3

어리석은 질문 인 경우 용서해주세요. 나는 몇 시간 동안 노력해 왔고 두뇌는 이제 막 작동을 멈췄다.

저는 세 가지 AJAX 호출로 구성된 시스템을 가지고 있습니다. 첫 번째 호출의 서버 응답은 일반적으로 입니다. 성공; 그러나 두 번째와 세 번째 쿼리는 이미지 업로드이기 때문에 깨지기 쉽고 서버 측에서는 클라이언트의 이미지가 대부분 실패하는 유효성 검사 규칙이 너무 많습니다. 위의 규정

window.AjaxCall = function() { 
    // to pass to $.ajax call later 
    this.args = arguments; 

    // xhr status 
    this.status = null; 

    // xhr results (jqXHR object and response) 
    this.xhrResponse = {}; 

    this.dfr = new $.Deferred(); 

    // to provide an easier interface 
    this.done = this.dfr.done; 
    this.fail = this.dfr.fail; 
    this.then = this.dfr.then; 
}; 

AjaxCall.prototype.resetDfr = function() { 
    this.dfr = new $.Deferred(); 
}; 

AjaxCall.prototype.resolve = function() { 
    this.dfr.resolve(
      this.xhrResponse.result, 
      this.xhrResponse.jqXHR 
    ); 

    this.resetDfr(); 
}; 

AjaxCall.prototype.reject = function() { 
    this.dfr.reject(
      this.xhrResponse.jqXHR 
    ); 

    this.resetDfr(); 
}; 

AjaxCall.prototype.query = function() { 
    var _this = this; 

    // if query hasn't run yet, or didn't return success, run it again 
    if (_this.status != 'OK') { 
     $.ajax.apply(_this, _this.args) 
       .done(function (result, textStatus, jqXHR) { 
        _this.xhrResponse.result = result; 
        _this.xhrResponse.jqXHR = jqXHR; 
        _this.resolve(); 
       }) 
       .fail(function (jqXHR) { 
        _this.xhrResponse.jqXHR = jqXHR; 
        _this.reject(); 
       }) 
       .always(function (a, b, c) { 
        var statusCode = (typeof c !== 'string' 
          ? c 
          : a).status; 

        if (statusCode == 200) { 
         _this.status = 'OK'; 
        } 
       }); 
    } 

    // if query has been run successfully before, just skip to next 
    else { 
     _this.resolve(); 
    } 

    return _this.dfr.promise(); 
}; 

AjaxCall 클래스이며,이 같은 세 개의 연속 호출합니다

var First = new AjaxCall('/'), 
     Second = new AjaxCall('/asd'), 
     Third = new AjaxCall('/qqq'); 

First.then(function() { 
    console.log('#1 done'); 
}, function() { 
    console.error('#1 fail'); 
}); 

Second.then(function() { 
    console.log('#2 done'); 
}, function() { 
    console.error('#2 fail'); 
}); 

Third.then(function() { 
    console.log('#3 done'); 
}, function() { 
    console.error('#3 fail'); 
}); 

var toRun = function() { 
    First.query() 
      .then(function() { 
       return Second.query(); 
      }) 
      .then(function() { 
       return Third.query() 
      }); 
}; 

$('button').click(function() { 
    toRun(); 
}); 

그 코드는 테스트 환경에 있습니다. 그리고 테스트 환경에서는 간단한 HTML 페이지와 디버깅을위한 기본적인 서버 지원을 의미합니다.

  • 홈 페이지 (/)는 항상 200 성공를 반환합니다.
  • /ASD 반환 (404)는 처음 3 번200 성공번 패턴으로 (즉 세 404을를 찾을 수 없음 -> 하나 (200) -> 세 404 -> 하나 (200) -> 세 404s -> ...).
  • /qqq404를 찾을 수 없습니다. 항상입니다.

페이지의 유일한 단추를 누르면 첫 번째 쿼리는 성공을 반환하고 두 번째는 예상대로 실패합니다. 버튼을 두 번째로 클릭하면 첫 번째 쿼리는 지난 번 성공했기 때문에 건너 뛰었고 두 번째 쿼리는 예상대로 실패했습니다.

문제는 여기에 있습니다 :

  • 나는 dfr이 alreay 해결 또는 거부하기 때문에, 그것은 더 이상 resolvereject 방법에 반응하지 않는 resetDfr 방법을 사용하기 전에. 내가 예에 표시하는 방식으로 resetDfr 메서드를 호출 할 때
  • , dfr 해결하거나 다시을 거부 할 수 있지만 이전 dfr의 콜백은 새로운 dfr 개체와 바인더 제본되지 않고 내가 할 수 없었다 이전의 콜백을 새로운 dfr으로 복제하는 방법을 찾으십시오.

내가 여기서하려는 일을 수행하기위한 귀하의 제안은 무엇입니까?

+0

그것은 당신이 실현하려 시도하고있는 무슨 질문에서 실제로 분명하지 않다. 지연된 콜백을 복제하고 싶습니다. 그러나 무엇을 위해? 클릭 할 때마다 모든 요청을 다시 실행 하시겠습니까? 왜 이러한 요청은 병렬로 실행되지 않고 연속적으로 실행되어야합니까? –

+0

@ YuryTarabanko 요청은 실제 제품에서 첫 번째 쿼리가 양식 필드를 데이터베이스 테이블에 저장하고 ID가있는 응답을 저장하기 때문에 연속적이어야합니다. 다른 검색어는 해당 ID와 함께 전송됩니다. ** 전에 실패한 경우 ** 요청을 다시 실행하고 싶습니다. 사용자가 요청을 보내면 서버에 오류가 있음을 알리는 메시지가 표시되면 사용자에게 오류에 대해 경고하여 입력 (이미지)을 적절하게 변경하고 다시 시도 할 수 있습니다. – Hkan

답변

1

약속은 단일 값을 시간 단위로 표시합니다. 당신은 개념적으로 지연된 것을 "재사용"하거나 리셋 할 수 없습니다. 여러 값 (observables와 같은)에 대한 약속을 일반화하는 구문이 있지만이 경우 더 복잡합니다. 요청 당 지연된 것을 사용하는 것이 좋습니다.

jQuery의 AJAX 은 이미 약속있는 인터페이스을 제공합니다. 코드는 대부분 중복되어 있으므로 기존 툴링을 사용해도되고 사용해야합니다. $.get에서

살펴 보자 : 자신이 연기 만들 필요가 없습니다

  • 그것은 이미 약속을 반환합니다. 서버가 HTTP 캐싱을 금지하거나 브라우저가 올바른 응답이 도착 후 단 하나 개의 요청이 서버에 이루어집니다 거부하지 않는 한
  • 그것은 이미, 브라우저 캐시를 사용 (명시 적으로 매개 변수에 {cache: false}를 통과하지 못한 당신 가정.
포스트 요청을하는 경우

당신은 $.post 또는 임의의 옵션에 대한 더 일반적으로 $.ajax을 사용할 수 있습니다

를이 코드는 대략 같을 것이다 방법입니다.

$("button").click(function(){ 
    var first = $.get("/"); 
    var second = first.then(function(){ 
     return $.get("/asd"); 
    }); 
    var third = second.then(function(){ 
     return $.get("/qqq"); 
    }); 
}); 

내가 변수에 넣는 이유는 나중에 first.then 등을 수행하여 결과를 직접 래핑 할 수 있기 때문입니다. 단일 체인에서도이 작업을 수행 할 수 있습니다 (단, 그들을 명시 적으로 저장하지 마십시오. 기록을 위해

- 그것은 바보 같은 질문은 전혀하지 않았다 :)

+0

내가 전에 쓴 모든 코드를 없앴습니다. 나는 당신의 본보기를 사용했습니다. 나는 각각의 요청에 대해'.fail' 콜백을 제공했다. 두 번째 및 세 번째 요청의 실패 콜백 발생 모두 두 번째 요청이 실패 할 때 문제가 발생합니다. 그게 나에게 문제를 일으킬 지 모르겠지만 이것이 예상 된 행동인지 궁금하다. – Hkan

+0

@ HakanAktaş 예 - 동기 코드에서 이것은'function f()'가'function g()'을 호출하고'g'가 throw되는 것과 같습니다 - 만약'f' 자체 내에서 또는' g' - 당신의 코드는'f'를 호출하는 사람의 catch 핸들러에 도달합니다. 아직 명확하지 않은 경우 별도의 질문을하는 것이 좋습니다. –