유데미 리액트 강의 27. 비동기 작업 처리 2. Promise

devBear·2024년 10월 10일


비동기 작업의 결과값을 다른 비동기 작업의 인수 값으로 넣어주는 형태로

코드를 작성하다 보면

위 이미지처럼 indent(들여쓰기)가 점점 깊어지는 형태로 바뀔 우려가 있고

이것은 코드의 가독성을 해치는 큰 요인이 된다.

이것을 방지하기위해 쓰이는 Promise라는 객체가 있다!


🤔 Promise란?

비동기 작업을 효율적으로 처리할 수 있도록 도와주는

JavaScript의 내장 객체

Promise 객체는 비동기 작업을 래핑한 형태를 띄고 있다.


🤔 Promise의 효능은 뭐가 있을까?


핵심 기능

  • 비동기 작업 실행
  • 비동기 작업상태 관리
  • 비동기 작업 결과 저장

그 외의 기능들

  • 비동기 작업 병렬 실행
  • 비동기 작업 다시 실행
  • 기타 등등...

📚 Promise의 3가지 상태


대기 (Pending)

  • 아직 작업이 완료되지 않은 상태

성공 (Fulfilled)

  • 비동기 작업이 성공적으로 마무리 된 상태

실패 (Rejected)

  • 비동기 작업이 실패한 상태

대기(Pending) -> 성공(Fulfilled)

대기 상태에서 성공 상태가 되어지는 것을 resolve(해결)되었다고 한다.


대기(Pending) -> 실패(Rejected)

대기 상태에서 실패 상태가 되어지는 것을 reject(거부)되었다고 한다.


💡 좀더 쉽게 이해해볼까?



이런식으로 유튜브 영상을 시청하려고 로딩화면의 상태인 것을

대기(pending)상태 라고 생각하면 된다.

그리고 영상 로딩이 완료되어져서 영상 시청이 가능해지는 상태가 되어가는 것은

해결(resolve) 라고 보면 된다.

최종적으로 시청이 가능해진 상태 자체를

성공(Fulfilled) 상태라고 생각하면 된다.



반대로 영상 로딩에 실패한 것은 거부 (reject) 상태이다.


최종적으로 영상 시청이 불가능한 상태가 되어지는 것은 실패(Rejected) 상태가

된 것이라 생각하면 된다.


📚 실습 예제



promise 객체를 하나 만들어보자

위 이미지에서 Promise 객체 내에서 비동기 작업을 실행하는 함수를

executor라고 부른다. 객체를 만들고 해당 객체를 출력해보면



[[PromiseState]] 는 Promise 객체의 상태라고 보면된다. 현재 "pending"상태로

대기 상태라고 보면 된다.

[[PromiseResult]]은 결과값이라고 보면 되고 아직 대기 상태이므로

undefined 인 것을 확인할 수 있다.

이러한 Promise 객체 가 executor 함수의 비동기 작업을

어떤 상태로 만들지 분기별로 확인해보자


💻 실습 1. - Promise가 executor의 작업을 성공하게 해보자



먼저 executor 함수에 전달 될 두가지의 매개변수를 추가해준다.

resolve는 Promise가 관리하는 비동기 작업을 성공 상태로 바꾸는 함수가 들어있고

reject는 Promise가 관리하는 비동기 작업을 실패 상태로 바꾸는 함수가 들어있다.

이 executor에서 실행하는 작업을 성공했다고 알리고 싶으면

resolve(); 이런식으로 resolve 함수를 호출해주면 된다.

성공 상태가 된 Promise를 다시 한번 출력하게끔 동작을 설정하고 콘솔에 출력해보면


[[PromiseState]]가 "fuilfilled"가 된 것을 확인할 수 있다.

하지만 [[PromiseResult]]는 여전히 undefined인 것을 볼 수 있다.

resolve();를 호출할 때 인수로 아무것도 전달하지 않았기 때문이다.


이런식으로 resolve();를 호출할 때 "안녕"이라는 인수를 전달하도록 수정하면?



이런식으로 Promise의 결과인 [[PromiseResult]]가 "안녕"이라는

결과를 출력하는 것을 확인할 수 있다.


💻 실습 2. - Promise가 executor의 작업을 실패하게 해보자


성공했을 때의 케이스와 다르게 reject();를 호출하여

이번엔 실패하게끔 만들어볼까? reject();의 인수 안에는

왜 실패했는지 이유를 적으면 된다고 생각하면 된다.



2초 뒤 안녕이 출력되어지고 3초 뒤 Promise 객체를 출력해보면 이런식으로 에러 문구와 함께

이유와 함께 출력되어지고 상태와 결과가 함께 출력된다.


🤔 결론은?


executor 함수에서 reject를 호출하게 되면 비동기작업에 실패하게 되는 것이고

반대로 resolve를 호출하게 되면 비동기작업에 성공하게 되는 것이라고 생각하면 된다.

그리고 각각 두 함수 모두 인수로 Promise의 결과값을 전달할 수 있다.


이번엔 이런 Promise 객체를 이용하는 방법에 대해서 예제를 통해 실습해보겠다.


💻 실습 3. Promise를 이용하는 법


주어진 num 이라는 변수가 하나 있을 때

변수의 타입이 만약 숫자라면

resolve();를 호출시켜 성공시키고 결과값엔 숫자에 10을 더하여 전달하고

아니라면 reject();를 호출시키고 결과엔 주어진 변수가 숫자가 아니라는 실패의

이유를 전달한다.



정상적으로 num 변수에 숫자인 10을 전달하면

이런식으로 10 + 10 의 결과값인 20과 함께 성공에 대한 Promise를 출력한다.



만약 num 에 "숫자가아님" 형식으로 문자열을 전한다면?



이런식으로 실패인 reject();를 호출하면서

상태와 인수로 전달했던 이유를 출력한다.


💻 실습 4. Promise의 결과값까지 활용하는 방법 - then 메서드


Promise로 관리하는 비동기 작업에 성공하여 나온 결과값을 사용하려면 어떻게 해야할까?

바로 then 메서드를 사용하면 된다.


then 이란?

  • Promise 객체와 관련된 비동기 작업이 완료된 후의 처리 결과를 다루기 위해 사용됩니다.
  • Promise가 성공적으로 이행(fulfilled)되었을 때, then메서드는 그 결과 값을 받아서 처리할 수 있게 해준다.


then 메서드를 이용하여 결과값을 받아서 출력하는 동작을 해보자.



성공하여 결과값만 출력되는 것을 확인할 수 있다.



숫자가 아닌 문자열 등을 넣어 실패하면 then에 설정한 동작이 아닌

그저 에러와 이유만 출력되는 것을 확인할 수 있다.

then은 성공했을 때의 상황을 다루는 메서드이기 때문이다.

그럼 실패하였을 때의 상황을 다루려면 어떻게 해야될까?

바로 then의 반대버전인 catch가 존재한다.


catch 란?

  • catch 메서드는 Promise에서 발생한 오류(거부됨, rejected)를 처리하기 위해 사용됩니다.
  • Promise가 실패하거나 오류가 발생하면, catch 메서드가 호출되어 그 오류를 다룰 수 있다.
    catch는 then 메서드 체인의 마지막에 주로 위치하며, 오류를 잡아내는 역할을 한다.


then과 비슷하게 작성해주면 된다.



실패시에만 이런식으로 reject(); 인수로 전달했던 값이 출력되는 것을 확인할 수 있다.


💻 실습 4. Promise의 강력한 기능


Promise의 강력한 기능은 바로

then이 동일한 Promise를 똑같이 반환한다는 점이다.


그러므로 then과 catch를 굳이 따로 쓸 필요가 없이

둘을 연결해서 작성해도 동일하게 동작한다는 점이다.

이런 문법을 Promise chaining 이라고 부른다.



Promise chaining

  • then에서 Promise를 반환하면, 그 다음 then 또는 catch는 해당 Promise가 완료된 후 실행된다.
  • 이렇게 체인으로 여러 비동기 작업을 순차적으로 처리하거나, 오류를 한 곳에서 처리할 수 있다.

💻 실습 5. Promise 예제 - 값을 유동적으로 받아서 사용



이런식으로 add10라는 함수를 만들어 내부에 코드를 집어넣으면

더이상 const 변수로 고정적으로 값을 받는 게 아닌

호출할 때 인자로 값을 유동적으로 받아 매개변수로써 값을 다양하게 받아들일 수 있고

결과값으로 Promise를 반환하여 추후 다른 비동기 작업에 인수로써 활용할 수 있다.



이런식으로 10을 더하는 비동기 작업으로써 이어지는 결과로 잘 출력되어지는 것을 확인할 수 있다. 하지만 이런식으로 작성하게 되면 프로그래밍 세계에서 불려지는 콜백 지옥 처럼
계속해서 파고드는 들여쓰기 때문에 가독성이 매우 떨어지게 될 수 있다.


이를 방지하기 위해 존재하는 강력한 기능이 있다.


Promise 객체가 별도로 반환하는 것을 설정하지않으면

원본 Promise 객체를 반환했었지만 새로운 Promise를 반환하게끔 설정해주면

해당 then메서드의 실행 결과값이 새로운 Promise 값이 된다.


이런 식으로 특정 변수에 담을 필요없이

반환과 동시에 Promise 객체로 감싼 함수로 다시 호출하여

그냥 바로 then이나 catch에 활용하는 형식으로 이어줄 수 있다.

중간에 에러가 발생하더라도 catch에서 최종적으로 잡아서 에러 내용을 출력해준다.



이런식으로 중간에 에러를 발생할만한 코드가 있더라도 이어 실행하고 마지막에

에러 내용을 출력하는 것을 확인할 수 있다.

이런식으로 Promise를 사용하게 되면 비동기작업의 처리 결과값을 또 다른

비동기작업에 활용하더라도 간결하고 가독성있게 작성이 가능하다.



profile
개발하는 곰🐻

0개의 댓글