JAVASCRIPT

JS Promise란

역발산기개세 2020. 1. 14. 17:57

Promise는 JS 비동기 처리에 사용되는 객체입니다.

여기서 JS 비동기 처리란 '특정 코드의 실행이 완료될 때까지 기다리지않고 다음 코드를 먼저 수행하는 JS의 특징'을 의미합니다.

프로미스는 주로 서버에서 받아온 데이터를 화면에 표시할 떄 사용합니다.

 

Promise 예제 코드

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

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

위 코드는 제이쿼리의 ajax 통신을 이용하여 지정한 url에서 1번 상품 데이터를 받아오는 코드입니다. 비동기 처리를 위해 프로미스 대신에 콜백 함수를 이용했습니다.

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에 전달됨
});

콜백 함수로 처리하던 구조에서 new Promise(), resolve(), then()와 같은 프로미스API를 사용한 구조로 바뀌었습니다.

 

프로미스의 3가지 상태(states)

프로미스를 사용할 떄 알아야 하는 가장 기본적인 개념이 바로 프로미스의 상태(states)입니다. 여기서 말하는 상태란 프로미스의 처리 과정을 의미합니다. new Promise()로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖습니다.

- pending(대기): 비동기 처리 로직이 아직 완료되지 않은 상태

- Fullfilled(이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

- Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태

 

Pending(대기)

new Promise() 메서드를 호출하면 Pending(대기) 상태가 됩니다. 호출할 떄 콜백 함수의 인자로 resolve, reject에 접근 할 수 있습니다.

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

Fullfilled(이행)

resolve()를 실행하면 Fullfilled(이행) 상태가 됩니다. 그리고 이행 상태가 되면 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
});

Rejected(실패)

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolve와 reject를 사용할 수 있다고 했습니다. 여기서 reject 인자로 reject() 메서드를 실행하면 Rejected(실패)상태가 됩니다. 그리고, 실패 상태가 되면 실패한 이유를 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
});

프로미스 코드 - 예제

function getData() {
  return new Promise(function (resolve, reject) {
    $.get('url 주소/products/1', function (response) {
      if (response) {
        resolve(response);
      }
      reject(new Error("Request is failed"));
    });
  });
}

// Fulfilled 또는 Rejected의 결과 값 출력
getData().then(function (data) {
  console.log(data); // response 값 출력
}).catch(function (err) {
  console.error(err); // Error 출력
});

위 코드는 서버에서 제대로 응답을 받아오면 resolve() 메서드를 호출하고, 응답이 없으면 reject() 메서드를 호출하는 예제입니다. 호출된 메서드에 따라 then()이나 catch()로 분기하여 데이터 또는 오류를 출력합니다.

프로미스 에러 처리는 가급적 catch()로

// then()의 두 번째 인자로는 감지하지 못하는 오류
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result);
  throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then()
}, function (err) {
  console.log('then error : ', err);
});

getData() 함수의 프로미스에서 resolve() 메서드를 호출하여 정상적으로 로직을 처리했지만, then()의 첫 번째 콜백 함수 내부에서 오류가 나는 경우 오류를 제대로 잡아내지 못합니다.

하지만 똑같은 오류를 catch()로 처리하면 다른 결과가 나옵니다.

// catch()로 오류를 감지하는 코드
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result); // hi
  throw new Error("Error in then()");
}).catch(function (err) {
  console.log('then error : ', err); // then error :  Error: Error in then()
});

발생한 에러를 성공적으로 콘솔에 출력합니다. 따라서, 더 많은 예외 처리 상황을 위해 프로미스의 끝에 가급적 catch()를 붙이는 것을 권장합니다.