Welcome :っ)

Devlog/JavaScript

[JavaScript] Promise 알아보기

lazy.won 2022. 6. 29. 18:19
728x90
반응형

 

 

 

 

 

막연하게만 알고 있던 Promise가 대체 무엇이고, 왜 등장하게 되었는지, 어떤 방식으로 사용할 수 있는지 ! 

Lazywon 게을러지기 전에 제대로 한번 공부해보자 !  😂 

 

 

 

 

🦄 들어가기 앞서.. Promise의 등장 이유!?

자바스크립트에서 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다.

하지만 전통적인 콜백 패턴은 콜백 헬(Callback Hell)로 인해 가독성이 나쁘고 비동기 처리 중 발생한 에러 처리가 곤란하며, 여러 개의 비동기 처리를 한 번에 처리하는데 한계가 있다는 단점이 존재한다.

 

 

잠깐, Callback Hell 이 뭔데?

..을 알아보기 전에 먼저 동기식 처리 모델과 비동기식 처리 모델에 대해 공부해보자 !

 

동기식 처리 모델

  • 태스크가 순차적으로 실행되며, 어떤 작업이 수행 중이면 해당 작업이 끝날 때까지 다음 태스크는 대기(Blocking)하게 되는 것.

 

비동기식 처리 모델

  • 태스크가 종료되지 않은 상태라 하더라도 대기하지 않고 (Non-Blocking) 즉시 다음 태스크를 병렬적으로 수행하는 것.자바스크립트의 대부분의 DOM 이벤트와 Timer 함수(setTimeout, setInterval), Ajax 요청은 비동기식 처리 모델로 동작한다.

 

비동기식 처리 모델은 요청을 병렬로 처리하여 다른 요청이 블로킹 (작업 중단) 되지 않는 장점이 있지만, 

비동기 처리를 위해 콜백 패턴을 사용하면 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 네스팅(nesting, , 중첩)되어 복잡도가 높아지는 콜백 헬(Callback Hell)이 발생하는 단점이 있다. 콜백 헬은 가독성을 나쁘게 하며 실수를 유발하는 원인이 된다.

 

또한 비동기 함수의 처리 결과를 반환하는 경우, 순서가 보장되지 않기 때문에 그 반환 결과를 가지고 후속 처리를 할 수 없다.

즉, 비동기 함수의 처리 결과에 대한 처리는 비동기 함수의 콜백 함수 내에서 처리해야 한다. 이로 인해 콜백 헬이 발생하는  것이다. 

Callback Hell은 코드의 가독성을 나쁘게 하고 복잡도를 증가시켜 실수를 유발하는 원인이 되며 에러 처리가 곤란하다.

비동기 함수의 콜백 함수 내에서 발생시킨 에러는 catch 블록에서 캐치되지 않아 프로세스는 종료된다.

 

 

이런 문제를 극복하기 위해서 ES6에서 비동기 처리를 위한 패턴으로 프로미스(Promise)를 도입했다. 전통적인 콜백 패턴이 가진 단점을 보완하면서 비동기 처리 시점도 명확하게 표현할 수 있다는 장점이 있다.  

 

그래서 , Promise가 뭔데?

Promise는 간단하게 자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 오브젝트이다.

정해진 장시간의 기능을 수행하고 나서 정상적으로 기능 수행이 되었다면 성공 메시지와 함께 처리된 결괏값을 전달해주고, 만약 기능을 수행하다가 예상치 못한 문제가 발생한 경우, 에러를 전달해 준다. 

 

 

 

 

⭐ Promise 객체 생성과 실행

Promise는 크게 Producer와 Consumer로 나눌 수 있다. 즉, 원하는 데이터를 제공하는 사람(producer)과 제공된 데이터를 소비하는 사람(consumer)으로 나누어 알아보자.

 

 

Promise Producer

Promise는 비동기 처리가 성공했는지, 실패했는지 등의 상태 정보를 갖는다. 생성하고 종료될 때까지 아래와 같은 3 가지 상태를 갖는다. 

 

Pending(대기)
아직 비동기 처리 로직이 완료되지 않고 수행 중인 상태(fulfilled 혹은 rejected가 되기 전)


Fulfilled(이행) 
비동기 처리가 완료되어 Promise가 결과 값을 반환해준 상태


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

 

 

// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행한다.

  if (/* 비동기 작업 수행 성공 */) {
    resolve('result');
  }
  else { /* 비동기 작업 수행 실패 */
    reject(Error('failure reason'));
  }
});

 

Promise는 클래스이기 때문에, new Promise()로 프로미스 오브젝트를 생성한다.

Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달받는데, 이 콜백 함수는 resolve와 reject 함수를 인자로 전달받는다.

인자로 전달받은 콜백 함수는 내부에서 비동기 처리 작업을 수행한다.

이때 비동기 처리가 성공하면 콜백 함수의 인자로 전달받은 resolve() 함수를 호출한다. (이때, Promise는 fulfilled 상태가 된다. )

비동기 처리가 실패하면 콜백함수의 인자로 전달받은 reject() 함수를 호출한다. (이때, Promise는 rejected 상태가 된다. )

 

 

❗ 여기서 주의해야 할 프로미스의 특징이 있다 ❗

Promise를 만드는 순간, 전달한 콜백 함수가 바로 실행된다는 것이다. 

그래서 생성되자마자 불필요한 네트워크 통신이나 무거운 비동기 처리 작업들을 하게 될 수도 있기 때문에, 코드 작성 시 유의하도록 하자 !

 

 

 

Promise Consumer

Promise로 구현된 비동기 함수는 Promise 객체를 반환한다. Promise로 구현된 비동기 함수를 호출하는 측(promise consumer)에서는 Promise 객체의 후속 처리 메서드 then, catch, finally를 이용해 값을 받아올 수 있다. 

 

promise.then((value) => {
    console.log(value); 
})
.catch((error) => {
    console.log(error); 
});
.finally(() => {
    console.log('finally...!'); 
});

 

then
then 메서드는 두 개의 콜백 함수를 인자로 전달 받는다. 첫 번째 콜백 함수는 성공(fulfilled, resolve 함수가 호출된 상태) 시 호출되고 두 번째 함수는 실패(rejected, reject 함수가 호출된 상태) 시 호출된다. then 메소드는 값을 바로 전달할 수도 있고, 또 다른 비동기인 Promise를 전달할 수도 있다.


catch
예외(비동기 처리에서 발생한 에러와 then 메서드에서 발생한 에러)가 발생하면 호출된다. 
  • 비동기 처리 시에 발생한 에러는 then 메서드의 두 번째 콜백 함수로 처리할 수 있다.
  • 비동기 처리에서 발생한 에러는 Promise 객체의 후속 처리 메서드 catch를 사용해서 처리할 수도 있다.
catch 메서드를 모든 then 메서드를 호출한 이후에 호출하면 비동기 처리에서 발생한 에러(reject 함수가 호출된 상태)뿐만 아니라 then 메서드 내부에서 발생한 에러까지 모두 캐치할 수 있기 때문에, Promise 에러 처리는 가급적 then 메서드에서 하지 말고 catch 메서드를 사용하는 것을 권장한다.


finally
성공 실패와 상관없이 무조건 마지막에 호출된다.

 

 

Promise의 then을 호출하게 되면 then은 결국 같은 프로미스를 반환하기 대문에 그 반환된 프로미스의 catch를 다시 호출할 수가 있다. 이것을 Chaining이라 한다. 

 

 

 

 

🔗 Promise Chaining

비동기 함수 처리 결과를 가지고 다른 비동기 함수를 호출해야 하는 경우, 함수 호출이 중첩되어 복잡도가 높아지는 콜백 헬이 발생한다고 했다.

 

Promise는 후속 처리 메서드를 체이닝(chainning)하여 여러 개의 프로미스를 연결하여 사용할 수 있다. 이로써 콜백 헬을 해결할 수 있다.

 

Promise 객체를 반환한 비동기 함수는 프로미스 후속 처리 메서드인 then이나 catch 메서드를 사용할 수 있다. 따라서 then 메서드가 Promise 객체를 반환하도록 하면(then 메서드는 기본적으로 Promise를 반환한다.) 여러 개의 프로미스를 연결하여 사용할 수 있다. 

 

then() 메서드를 호출하고 나면 새로운 프로미스 객체가 반환되어 아래와 같이 여러 개의 프로미스를 연결한 방식으로 코딩이 가능하다.

 

promise.then((value) => {
    // ...
  })
  .then(() => {
    // ...
  })
  .then(() => {
    // ...
  });

 

 

 

 

 

 

 

 

 

참고

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

Promise - JavaScript | MDN

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

developer.mozilla.org

https://poiemaweb.com/es6-promise

 

Promise | PoiemaWeb

Promise는 비동기 처리가 성공(fulfilled)하였는지 또는 실패(rejected)하였는지 등의 상태(state) 정보를 갖는다. Promise는 Promise 생성자를 통해 인스턴스화한다. Promise 생성자는 비동기 작업을 수행할 콜

poiemaweb.com

 

320x100
반응형