Promise와 Callback

Min·2021년 1월 7일
0

JavaScript

목록 보기
11/18
post-thumbnail

사용자가 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 줄지도 모른다면?

마냥 다른 코드를 실행 안 하고 기다릴 순 없다. 만약 요청이 50개라면 그 50개가 다 수행될 때까지 웹 어플리케이션을 제대로 이용할 수 없기 때문이다. 이러한 순간에 필요한 것이 비동기 실행이다. 그 비동기 실행을 구현하기 위해 사람들은 Callback function을 사용하였고, Callback function의 여러 단점을 보완하기 위해 등장한 것이 Promise이다.


출처 링크

Callback

function getData(callbackFunc) {
  $.get('url 주소/products/1', function(response) {
    callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
  });
}

getData(function(tableData) {
  console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});

단점

  1. 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 네스팅(nesting, 중첩)되어 복잡도가 높아진다. 복잡해진 코드는 위와같이 콜백 헬을 발생시키는데, 콜백 헬은 가독성이 좋지 않아 실수를 유발하는 원인이 된다
  2. 여러 개의 비동기 로직을 한꺼번에 처리하는 데에 한계가 있다.
  3. error 처리에 한계가 있다.
try {
  setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
  console.log('에러를 캐치하지 못한다..');
  console.log(e);
}

위 코드의 실행 과정이다.

try 블록 내에서 setTimeout 함수가 실행 됨 >> 1초 후 콜백 함수 실행 >> 콜백 함수가 예외(exception)를 발생시킴 >> 하지만 예외가 catch 블록에서 캐치되지 않음


setTimeout 함수는 *비동기 함수이므로 콜백 함수가 실행될 때까지 기다리지 않고 즉시 종료되어 호출 스택에서 제거된다.

이후 tick 이벤트 발생 >> setTimeout 함수의 콜백 함수는 태스트 큐로 이동 >> 호출 스택이 비어졌을 때 호출 스택으로 이동되어 실행

순으로 코드가 진행되는데,

이때 setTimeout 함수는 이미 호출 스택에서 제거된 상태이다. 이것은 setTimeout 함수의 콜백 함수를 호출한 것은 setTimeout 함수가 아니다라는 것을 의미한다. setTimeout 함수의 콜백 함수의 호출자(caller)가 setTimeout 함수라면 호출 스택에 setTimeout 함수가 존재해야 하기 때문이다.

예외(exception)는 호출자(caller) 방향으로 전파된다. 하지만 setTimeout 함수의 콜백 함수를 호출한 것은 setTimeout 함수가 아니기 때문에 setTimeout 함수의 콜백 함수 내에서 발생시킨 에러는 catch 블록에서 캐치되지 않고, 프로세스는 종료된다.

비동기 처리 함수의 콜백 함수는 해당 이벤트(timer 함수의 tick 이벤트, XMLHttpRequest의 readystatechange 이벤트 등)가 발생하면 태스트 큐(Task queue)로 이동한 후 호출 스택이 비어졌을 때, 호출 스택으로 이동되어 실행된다.

Promise

function getData(callback) {
  // new Promise() 추가
  return new Promise(function(resolve, reject) {
    $.get('url 주소/products/1', function(response) {
      // 데이터를 받으면 resolve() 호출
      resolve(response);
    });
  });
}

// getData()의 실행이 끝나면 호출되는 then()
getData().then(function(tableData) {
  // resolve()의 결과 값이 여기로 전달됨
  console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});

3가지 상태

Promise는 new Promise()로 생성되고 종료할 때까지 3가지 상태를 갖는다.

  • Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
  • Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

1) Pending(대기)

new Promise() 메서드를 호출하면 대기(Pending) 상태가 된다.

new Promise();

new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject이다.

```js
new Promise(function(resolve, reject) { 
	// ... 
});

2) Fulfilled(이행 혹은 완료)

여기서 콜백 함수의 인자 resolve를 아래와 같이 실행하면 이행(Fulfilled) 상태가 된다.

new Promise(function(resolve, reject) {
  resolve();
});

이행 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있다.

function getData() {
  return new Promise(function(resolve, reject) {
    var data = 100;
    resolve(data);
  });
}

// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
  console.log(resolvedData); // 100
});

3) Rejected(실패)

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolve와 reject를 사용할 수 있다. 여기서 reject를 아래와 같이 호출하면 실패(Rejected) 상태가 된다.

new Promise(function(resolve, reject) {
  reject();
});

그리고, 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있다.

function getData() {
  return new Promise(function(resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
  console.log(err); // Error: Request is failed
});

장점

  1. 후속 처리 메소드를 체이닝(chainning)하여 여러 개의 promise를 연결하여 사용할 수 있다. 콜백 헬 해결!
  2. 상대적으로 가독성이 떨어지는 callback 패턴을 대체하여 async 함수도 sync 함수인 것 같은 flat 한 모양으로 코드를 작성할 수 있다.
  3. error 처리
promiseAjax('GET', 'http://jsonplaceholder.typicode.com/posts/1')
  .then(JSON.parse)
  .then(render)
  .catch(console.error);

1) then

  • 두 개의 콜백 함수를 인자로 전달 받는다. 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출되고 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다.
  • Promise를 반환한다.

2) catch

  • 예외(exception)(비동기 처리에서 발생한 error, then 메소드에서 발생한 error)가 발생하면 호출된다.
    (두 error를 다 캐치하므로, error처리는 catch 메소드를 사용하는 편이 효율적이다)
  • Promise를 반환한다.

참고 자료
[JavaScript] 바보들을 위한 Promise 강의 - 도대체 Promise는 어떻게 쓰는거야?
자바스크립트 Promise 쉽게 이해하기
Promise | PoiemaWeb
자바스크립트 비동기 처리와 콜백 함수

profile
slowly but surely

0개의 댓글