게시글

강좌13 - jQuery - 5년 전 등록 / 3달 전 수정

제이쿼리 프로미스(promise)와 Deferred

안녕하세요. 이번 시간에는 제이쿼리의 프로미스 기능과 deferred 객체에 대해 알아보겠습니다. 지난 AJAX 시간에도 살짝 다뤘는데요. 프로미스를 사용하면 비동기 프로그래밍을 할 때 코드를 간결하게 관리할 수 있습니다.

제이쿼리 프로미스는 기본적으로 공식 구현을 따르지 않아서 문제가 있습니다. 에러 처리와 프로미스 실행 순서에 관한 문제입니다. 하지만 복잡한 프로미스를 구현하지 않는 이상은 그 문제가 발생하지 않기 때문에 그냥 사용하셔도 됩니다. (제이쿼리 3.0에서는 그 문제가 해결되었습니다)

제이쿼리는 프로미스를 사용할 수 있게 Deferred라는 객체를 제공합니다. 이 객체를 사용하면 일반 코드도 프로미스처럼 사용할 수 있습니다.

일단 제이쿼리 프로미스의 기본 구조는 프로미스 객체가 완료되었을 때 done 메소드가 호출되고 실패했을 때는 fail, 완료되었건 실패했건 행동이 끝났으면 always가 호출됩니다. 콜백 기반 함수가 다음과 같이 있다고 가정해봅시다.

var longAndComplicatedFunction = function(cb) {
  console.log('시작');
  try {
    // 로직
    cb(null, '성공');
  } catch (err) {
    cb(err);
  } finally {
    console.log('완료');
  }
};
longAndComplicatedFunction(function (err, result) {
  if (err) {
    return console.error(err);
  }
  console.log(result);
});

이를 프로미스 기반으로 수정해봅시다..

$.Deferred

var longAndComplicatedFunction = function() {
  var deferred = $.Deferred();
  console.log('시작');
  try {
    // 로직
    deferred.resolve('성공');
  } catch (err) {
    deferred.reject(err);
  }
  return deferred.promise();
};
longAndComplicatedFunction().done(function(message) {
  console.log(message);
}).fail(function(error) {
  console.error(error);
}).always(function() {
  console.log('완료!');
});

이렇게 $.Deferred()로 deferred 객체를 만들고, 성공했을 때에는 resolve, 실패했을 때에는 reject 메소드를 호출하면 resolve는 done으로, reject는 fail로 연결됩니다. longAndComplicatedFunction 함수에서 deferred.promise()를 return하는 것을 잊지 마세요!

참고로 done이나 fail로 구분하지 않고 한 번에 처리하려면 then 메소드가 있습니다. 첫 번째 인자는 성공 시 콜백이고, 두 번째 인자는 실패 시 콜백입니다. then도 연달아 쓸 수 있습니다.

longAndComplicatedFunction().then(function(message) {
  console.log(message);
}, function(error) {
  console.error(error);
}).then(function() {
  console.log('완료!');
});

여기까지는 흔한 제이쿼리 프로미스 방식이고 ES2015의 프로미스와도 상당히 유사합니다. 제이쿼리의 장점은 추가 메소드를 제공하는 겁니다.

$.when

$.when은 여러 개의 비동기 프로미스 함수를 동시에 처리할 수 있게 해줍니다. Promise.all과 비슷합니다.

$.when(longAndComplicatedFunction(), longerAndMoreComplicatedFunction()).done(function(result1, result2) {
  console.log(result1, result2);
});

$.when 안에 여러 개의 프로미스 함수를 넣어줍니다. 함수들이 모두 종료되었을 때 연결해둔 done 메소드의 콜백이 실행됩니다. longAndComplicatedFunction의 결과는 result1으로, longerAndMoreComplicatedFunction의 결과는 result2로 연결됩니다.

여러 개의 프로미스를 동시에 처리할 수 있기 때문에 편리합니다. 특히 선행 조건으로 비동기 함수 여러개가 필요한 경우 $.when을 쓰면 효과적으로 코딩을 할 수 있습니다. done 메소드에서 비동기 함수의 결과들을 한 번에 받을 수 있으니까요.

이상으로 제이쿼리 강좌를 마치겠습니다. 혹시나 제이쿼리에 변경 사항이나 추가 사항이 있다면 그 때 포스팅하겠습니다!

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.

댓글

4개의 댓글이 있습니다.
3달 전
이거 deferred가 비동기로 동작하는거 맞나요?

얘기한 대로라면 위 예제에서 로직이 정상적으로 동작했다고 가정할때 출력순서가
1. '다음 행동'
2. '성공'
3. '완료'
이렇게 나와야 '비동기' 라고 할 수 있죠

그런데 실제로는
1. '성공'
2. '완료'
3. '다음 행동'
순으로 출력됩니다

즉 deferred 가 비동기로 동작하는것이 아닌
'약 50초가 걸리는 매우 복잡한 코드' 를 애초에 비동기로 작성했을때에
비로소 말씀하신 것처럼 비동기로 동작하겠죠

결과적으로 deferred, promise 가 비동기를 구현해 주는것이 아닙니다
애초에 약 50초 가량 걸리는 복잡한 코드를 비동기로 작성을 해야 하므로
그 경우에는 deferred 를 사용하지 않았을 때에도 동일한 결과를 가져 올 수 있습니다.

즉 deferred와 promise 의 사용의 이유는 '복잡한 비동기 구현'에 있는것이 아닌
로직이 정상적으로 잘 처리되었는지 그에대한 콜백을 좀 더 심플하고 논리적으로 구현하는데에
있습니다.

이거 비동기 구현으로 잘못알고 있는개발자들 많은거 같더라구요
3달 전
5년전에 쓴 글이네요. 저 때는 제가 초보여서 잘못 알고 있었습니다. ㅎㅎ 저건 Node의 util.promisify와 같네요. 단순히 콜백을 프로미스로 바꿔주는 용도 정도겠습니다.
3달 전
글 수정했습니다. 감사합니다.
3년 전
안녕하세요 혹시.. jquery pushStack()과 add() 차이점이 무엇인지 알려주실수 있을까요?
3년 전
https://stackoverflow.com/questions/17463575/difference-between-jquery-pushstack-and-add-method 여기에 나와있네요~ 새로운 DOM 객체를 생성하느냐가 차이인것 같아요
4년 전
업무에 큰 도움이 되었습니다. 감사합니다. ^^
5년 전
하루동안 재미있게 잘봤습니다 ㅎㅎ 감사합니다!
5년 전
감사합니다~