ajax 는 말그대로, 비동기 통신을 하기 위한, 도구이다.
jquery 에서는 $.ajax 또는 jQuery.ajax 라는 메서드를 통해서, 쉽게 ajax 를 이용할 수 있다.
내부적으로는 XMLHttpRequest 를 이용하고 있으며, 여러가지 편의 기능, option 을 제공하고 있다.
이중에서도, 매번 ajax 로 요청할때, 동일하게 사용하는 option / 처리가 끝나고 결과에(response) 대해 성공/실패/항상 처리해야 할일을
$.ajaxSetup 에 미리 정의해 놓으면, 코드양도 줄여주고, 간결해지게 된다.
여기서 다룰 내용은, $.ajax 요청이 비동기(asyncronous) 요청이기 때문에, 이를 위해, promise 처리를 하는 방법이다.
기본적으로, $.ajax 요청의 결과를 받는 방법으로 많이 사용되는것이,
complete
success
error
ajax 요청이 완료되고 결과(response) 가 나오면, 우선적으로, complete 에 정의된, 함수 (또는 콜백함수) 가 실행이 된다.
그리고 나서, 결과가 http 오류인지 http 성공(200 ok) 인지에 따라, success / error 에 정의된 함수 (또는 콜백함수) 가 실행이 된다.
이 방식은, 비동기 요청(ajax) 를 하고 나서, 처리결과에 따라, 다음 작업을 진행해야 할때마다, 매번 callback 함수를 사용해야 하는 문제를 발생시킨다. (불편한 코드의 문제...)
다행이도, $.ajax 는 위의 함수(또는 콜백함수) 기능외에 Promise 패턴이 적용되어 있다. (jquery 의 deferred 로 구현됨)
$.ajax({ url : '/post/url', data: 'param, ... } ).then( function(result, status, responseObj) {
성공일때 내용...
}, function (result, status, responseObj) {
실패일때 처리할 내용...
});
위와 같이 코드를 작성할 수 있다, 뒤의 실패일때의 function 부분은 생략도 가능하다.
이 코드는 다시 아래와 같은 형태로 변경이 가능다.
$.ajax({ url : '/post/url', data: 'param, ... } ).done( function(result, status, responseObj) {
성공일때 내용...
}).fail(function (result, status, responseObj) {
실패일때 처리할 내용...
});
then() 은 done(), fail() 로 분리해서 처리할수 있다.
성공/실패 여부와 상관없이 항상 실행해야 할 코드는 always() 에 넣어줄 수 있다.
$.ajax({ url : '/post/url', data: 'param, ... } ).done( function(result, status, responseObj) {
성공일때 내용...
}).fail(function (result, status, responseObj) {
실패일때 처리할 내용...
}).always(function (result, status, responseObj) {
항상 처리할 내용...
}); |
done() 이나 fail() 이 먼저 실행되고 난 후에 always 가 실행이 될것이다.
여기서 주의할 점은, $.ajax 의 promise 패턴은 http response 의 성공(200 ok) 이냐 실패냐에 기인한다는 점이다.
이는, 논리적인 성공 실패가 아니라, 물리적인 성공/실패를 의미하는 것이다.
웹서버에서 오류가 났을때, http 오류가 아니라, 적당한 오류 코드 와 오류 메세지를 response 해준다면, 어떨까?
그렇다면, $.ajax 는 이를 성공으로 간주하게 되어, 성공(done) 에서 논리적인 오류인지를 체크해야 한다.
이를 간소화 하기 위해서 아래와 같이 $.ajax 에 또다른 Promise 패턴을 적용한 래퍼함수(Wrapper) 를 만들 수 있다.
jquery 에서는 promise 패턴을 구현하기 위해, $.Deferred 라는 것을 제공하고 있다.
(실제 promise 패턴을 이용하기 위해 Promise 객체가 있지만, IE 에서는 지원하지 않기때문에, 호환성을 위해, $.deferred 를 사용했다.)
성공, 실패에 대해서는, resolve / reject 함수를 제공하며, 결과는 promise() 를 리턴해주면 된다.
$.ajax.promise = function (options) {
var deferred = $.Deferred();
$.ajax(
options
).done(function (result, status, responseObj) {
if (!result.bSuccess) // failed
{
deferred.reject(result, status);
return;
}
//data = JSON.parse(result.sJsonData);
data = ( result.sJsonData == null || result.sJsonData == "" ) ? null : JSON.parse(result.sJsonData);
deferred.resolve(result, data);
}).fail(function (result, status, responseObj) {
deferred.reject(result, status);
});
return deferred.promise();
} |
이 코드의 전제는 json 데이터를 받는다는 점이고, result 에 bSuccess 라는 속성이 존재한다는 점이다.
$.ajax 의 래퍼함수인 $.ajax.promise 를 이용하여, 위의 $.ajax promise 이용 예를 다시 호출해보면 아래와 같다.
$.ajax.promise({ url : '/post/url', data: 'param, ... } ).done( function(result, data) {
성공일때 내용...
}).fail(function (result, status, responseObj) {
실패일때 처리할 내용...
}).always(function (result, status, responseObj) {
항상 처리할 내용...
});
|
이제, 위 코드의 성공/실패 코드는 물리적인 http 오류외에도, 논리적인 오류에도 대응되는 코드로 변경이 된다.
위 코드는 단일 ajax 코드를 실행하는 방법이고, jquery 에서는 여러개의 promise 패턴을 처리하는 방법으로,
$.when 이라는 함수를 체공한다.
var pr1 = $.ajax.promise({ url : '/post/url', data: 'param, ... } );
var pr2 = $.ajax.promise({ url : '/post/url', data: 'param, ... } );
var pr3 = $.ajax.promise({ url : '/post/url', data: 'param, ... } );
$.when(pr1, pr2, pr3).done(function() {
모두 성공일때...
});
|
비동기 메서드이기 때문에, 위의 3줄은 같은 시기에 실행이 되지만, 결과는 제각각 다르게 나올것이다.
하지만, 모든 실행이 끝나고 나서, 처리해야할 내용이 있을때,
done() 함수에 넣어주면 된다.
$.when 도 promise 패턴으로 구현되어 있기 때문에,
done / fail / then 모두 사용가능하다.