[javascript] Promise

HongDuHyeon·2022년 2월 17일
0
post-thumbnail
개강까지 D-11

callback 지옥을 탈출하기엔 Promise만한게 없다고 많이 들었고 잘 사용하면 굉장히 편리하다고 들었다. 먼저 벨로퍼트님의 강의를 들어봤지만 아직은 잘 이해가 안간다. 어떤 상황에서 사용을 해야하는지도 감이 안잡힌다... 일단 강의 내용을 토대로 정리를 해봤다.

promise란?

비동기 작동을 좀 더 편하게 작업할 수 있도록 es6에 추가된 기능이다. 이전에는 "A작업이 끝나고 B작업이 실행되야한다"를 callback 함수로 처리했는데 callback으로 처리하게 될 경우 비동기 작업이 많아진다면 코드가 난잡해지게 된다.

(callback 지옥)

먼저 Promise 사용하지 않은 예제를 만들어보겠다.


숫자 n을 파라미터로 받고 5번에 걸쳐서 1초마다 1씩 더해보기

setTimeout으로 1초마다 1씩 증가하는 함수를 만들고 if문을 사용해서 만약 콜백이 있다라고 하면 1씩 더해주는 작업을 실행할 예정이다.

function print(n, callback) {
  setTimeout(() => {
    const increase = n + 1;
    console.log(increase);
    if (callback) {
      callback(increase);
    }
  }, 1000);
}

print(0, (n) => {
  print(n, (n) => {
    print(n, (n) => {
      print(n, (n) => {
        print(n, (n) => {
          console.log("작업끝");
        });
      });
    });
  });
});

지금은 그냥 숫자만 올라가는 기능을 구현한거라 억지로라도 보면 이거구나 하고 넘어갈 수 있지만 callback이 지금보다 많아진다면? 굉장히 난잡해지고 가독성도 떨어질 것이다. 그럼 이제 Promise를 사용해보자

Promise 사용해보기

먼저 Promise는 성공할 수도 있고, 실패할 수도 있다. 성공하면 resolve, 실패하면 reject를 사용한다. 성공과 실패 둘다 예제를 만들어보자

성공하는 예제

const callbackHell = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("result");
  }, 1000);
});

callbackHell.then((result) => {
  console.log(result);
});

Promise가 끝나고 어떠한 작업을 할게 있다면 then을 사용해주면 된다.

실패하는 예제

const err = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error());
  }, 1000);
});

err.then((result) => {
    console.log(result);
  }).catch((e) => {
    console.log(e);
  });

resolve말고 reject를 사용해서 new Error()를 넣어주고 에러를 잡는 기능인 catch를 사용한다.

Promise를 만드는 함수 구현

Promise를 사용해서 값이 5가 된다면 reject로 실패 처리가 되는 함수를 구현해보겠다.

function increaseAndPrint(n) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const value = n + 1;
      if (value === 5) {
        const error = new Error();
        error.name = "valueIsFiveError";
        reject(error);
        return;
      }
      console.log(value);
      resolve(value);
    }, 1000);
  });
}

increaseAndPrint(0)
  .then((n) => {
    return increaseAndPrint(n);
  })
  .then((n) => {
    return increaseAndPrint(n);
  })
  .then((n) => {
    return increaseAndPrint(n);
  })
  .then((n) => {
    return increaseAndPrint(n);
  })
  .then((n) => {
    console.log("result: ", n);
    return increaseAndPrint(n);
  })
  .catch((e) => {
    console.error(e);
  });

return으로 new Promise를 작성해주고 성공 지점, 실패 지점 코드를 setTimeout 안에 if문과 return으로 작성해준다. reject에 value값이 5가 되면 에러로 valueIsFiveError라는 이름을 가진 error를 출력해주고 성공시 resolve에 value값을 넣어준다.

그리고 하단에 increaseAndPrint에 초기값 0을 넣어주면 되는데 여기서 Promise 속성 중에 then에서 등록한 함수에다가 또 다른 Promise를 리턴하게 된다면 then을 연달아 사용가능한 속성이 있어서 밑에 쭉 써줬다. 하지만 지금 위에 코드를 보면 callback이랑 다를게 없다...

이럴 경우엔 then안에 함수를 넣어주면 된다!

function increaseAndPrint(n) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const value = n + 1;
      if (value === 5) {
        const error = new Error();
        error.name = "valueIsFiveError";
        reject(error);
        return;
      }
      console.log(value);
      resolve(value);
    }, 1000);
  });
}

increaseAndPrint(0)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .then(increaseAndPrint)
  .catch((e) => {
    console.error(e);
  });

이렇게 작성해주면 console창에

1
2
3
4
valueIsFiveError

이렇게 나오게 된다.

하지만 지금까지 썼던 것처럼 쓰게 되면 특정 조건에서 error를 잡기도 어렵고 만약 특정 조건에 따라 분기를 나눠야한다면 그것도 어려울뿐더러 특정 값을 공유해가면서 작업하기도 어렵다. 그래서 이때 사용하는게
async await이다.

profile
마음이 시키는 프론트엔드.. RN과 IOS를 곁들인..

0개의 댓글