[JS] 비동기 처리 (Promise)

j.log·2021년 10월 4일
2

JavaScript

목록 보기
11/11

자바스크립트는 비동기 작업을 동시에 할 수 있다.
자바스크립트는 코어 엔진만 가지고 돌아가지 않고, 실행환경(런타임)의 도움을 받아 동시 실행을 하기 때문이다!
(WebAPI(dom, ajax, setTimeout...), Task Queue, Event Loop 등과 함께 동작합니다.)



1. 콜백?

  • 콜백은 자바스크립트가 비동기 처리를 하기 위한 패턴 중 하나
  • 전통적인 콜백 패턴은 일명 콜백 헬로 불리는 엄청난 중첩 문제가 생기기 쉽다
  • 비동기 처리 함수 내에서 처리 결과를 반환하는 걸로는 원하는 동작을 하지 않으니, 콜백 함수를 사용해 원하는 동작을 하게 하려고 콜백 함수를 사용한다

1-1. 콜백 헬


  • 꼬리에 꼬리를 무는 비동기 처리가 늘어나면 호출이 계속 중첩되고, 코드가 깊어지고, 관리는 어려워진다.
  • 이런 깊은 중첩을 콜백 헬이나 멸망의 피라미드라고 부른다.
  function async1('a', function (err, async2){
      if(err){
          errHandler(err);
      }else{
          ...
          async2('b', function (err, async3){
              ...
          }){
              ...
          }
      }
  });

1-2. 콜백 헬이 발생하는 이유


  • 비동기 처리 시에는 실행 완료를 기다리지 않고 바로 다음 작업을 실행한다.
    즉, 순서대로 코드를 쭉 적는다고 우리가 원하는 순서로 작업이 이뤄지지 않는다는 것
  • 그래서 원하는 동작을 하게 하려고 콜백 함수를 사용하는데, 이 콜백 함수 내에서 또 다른 비동기 작업이 필요할 경우 위와 같은 중첩이 생기면서 콜백 헬이 탄생한다.😢



2. 프로미스 (promise)

비동기 연산이 종료된 이후 결과를 알기 위해 사용하는 객체
프라미스를 쓰면 비동기 메서드를 마치 동기 메서드처럼 값을 반환할 수 있다.
전통적인 콜백 패턴으로 인한 콜백 헬 때문에 ES6에서 도입한 또다른 비동기 처리 패턴입니다.
비동기 처리 시점을 좀 더 명확하게 표현할 수 있다!


2-1. 프라미스 후속 처리 - .then()


  • 프라미스로 구현된 비동기 함수는 프라미스 객체를 반환한다
  • 프라미스로 구현된 비동기 함수를 호출하는 측에서는,
    이 프라미스 객체의 후속 처리 메서드를 통해 비동기 처리 결과(성공 결과나 에러메시지)를 받아서 처리해야 한다
  • .then(성공 시 실행, 실패 시 실행)
    // 1. 프라미스를 하나 만들어 봅시다!
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve("완료!"), 1000);
    });

    // resolve
    promise.then(result => {
        console.log(result); // 완료!가 콘솔에 찍힌다
    }, error => {
        console.log(error); // 실행되지 않는다
    });
    // 2. 프라미스를 하나 만들어 봅시다!
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => reject(new Error("오류!")), 1000);
    });

    // reject
    promise.then(result => {
        console.log(result); // 실행되지 않는다
    }, error => {
        console.log(error); // Error: 오류!가 찍힌다
    });

2-1. 프라미스 실패 처리 - .catch()


    // 프라미스를 하나 만들어 봅시다!
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => reject(new Error("오류!"), 1000);
    });

    promise.catch((error) => {console.log(error};);



3. 프라미스 체이닝 (promise chaining)


  • 프라미스는 후속 처리 메서드를 체이닝해서 여러 개의 프라미스를 연결할 수 있다 (이걸로 콜백 헬을 해결할 수 있다)
  • 체이닝이란, 후속 처리 메서드 (then)을 쭉쭉 이어 주는 것!
    new Promise((resolve, reject) => {
        setTimeout(() => resolve("promise 1"), 1000);
    }).then((result) => { // 후속 처리 메서드 하나를 쓰고,
        console.log(result); // promise 1
        return "promise 2";
    }).then((result) => { // 이렇게 연달아 then을 써서 이어준다
        console.log(result);
        return "promise 3";
    }).then(...);



4. async & await

프라미스 사용을 엄청 편하게 만들어주는 친구! 💕


4-1. async


  • 함수 앞에 async를 붙여서 사용한다
  • 항상 프라미스를 반환한다.
    (프라미스가 아닌 값이라도, 프라미스로 감싸서 반환해줌)
    // async는 function 앞에 써줍니다.
    async function myFunc() {
        return "프라미스를 반환해요!"; // 프라미스가 아닌 걸 반환해볼게요!
    }

    myFunc().then(result => {console.log(result)}); // 콘솔로 확인해봅시다!

4-2. await


  • async와 반드시 함께 사용한다 (await는 async의 짝꿍)
  • async 함수 안에서만 동작한다
  • await는 프라미스가 처리될 때까지 기다렸다가, 그 이후에 결과를 반환한다
  • await를 만나면, 실행이 잠시 중단되었다가 프라미스 처리 후에 실행을 재개한다
    즉, await를 쓰면 함수 실행을 기다리게 하는 것!
    async function myFunc(){
        let promise = new Promise((resolve, reject) => {
            setTimeout(() => resolve("완료!"), 1000);
        });

        console.log(promise);

        let result = await promise; // 여기서 기다리자!하고 신호를 준다

        console.log(promise);

        console.log(result); // then(후처리 함수)를 쓰지 않았는데도, 1초 후에 완료!가 콘솔에 찍힌다
    }



5. 비동기 처리의 특성 및 에러 처리 방법

profile
jlog

2개의 댓글

comment-user-thumbnail
2021년 10월 5일

async await가 도입된 후에 시작했다보니, 콜백지옥을 못겪어봤어요 ㅋㅋ

1개의 답글