[JS]Promise

김정현·2022년 6월 2일

개념 정리

목록 보기
4/9
post-thumbnail

Promise

promise

프로미스란 비동기 처리 상태와 결과를 관리하는 객체이다
프로미스는 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다

프로미스는 비동기 처리를 위한 전통적인 콜백 패턴이 가진 단점을 보완하기 위하여 도입되었으며 
비동기 처리 시점을 명확하게 표현할 수 있고
콜백 패턴에서 처리하기 어려웠던 에러를 처리할 수 있다는 장점이 있다

프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있다
다만 최종 결과를 반환하는 것이 아니라, 
미래의 어떤 시점에 결과를 제공하겠다는 약속(promise)를 반환한다

프로미스의 생성

//2024.07.02
const promise = new Promise((resolve, reject) => {
//promise는 resolve와 reject메서드를 매개변수로 가진다.
  setTimeout(() => {
    const num = "tes";

    if (typeof num === "number") {
      //resolve메서드는 promiseState를 fulfilled로 변경
      //resolve메서드의 인자가 promise값으로 반환됨
      resolve(num + 10);
    } else {
      //reject메서드는 promiseState를 rejected로 변경
      //reject메서드의 인자가 에러 메세지로 반환됨
      reject("type 에러");
    }
  }, 2000);
  return promise;
});

//promise가 성공했을 때 실행
//then은 resolve의 인자를 매개변수로 가진다.
promise.then((value) => {
  console.log(value);
});

//promise가 실패했을 때 실행
//catch는 reject의 인자를 매개변수로 가진다.
promise.catch((error) => {
  console.log(error);
});

//promise는 promise를 반환하기 때문에 체이닝이 가능하다.
promise
  .then((value) => {
    console.log(value);
  })
  .catch((error) => {
    console.log(error);
  });

프로미스의 상태(states)

프로미스는 3가지의 상태를 가진다

pending(대기)
fulfilled(비동기 처리 이행)
rejected(비동기 처리 실패)

fulfilled와 rejected상태를 묶어 settled상태라고 한다.
프로미스는 pending상태에서 settled상태가 될 수 있으나
반대로는 변할 수 없다.


프로미스 후속 처리 메서드

프로미스의 비동기 상태가 변화하면 이에 따른 후속 처리를 해야 한다
이를 위해 프로미스는 후속 메서드 then, catch, finally를 제공한다

then
catch
finally

세 개의 프로미스 후속 처리 메서드는 언제나 프로미스를 반환한다

then

then메서드는 두 개의 콜백 함수를 인수로 전달받는다

첫 번째 콜백 함수는 프로미스가
fulfilled상태(resolve함수가 호출된 상태)가 되면 호출된다
이 때, 콜백 함수는 프로미스의 비동기 처리 결과를 인수로 전달받는다

두 번쨰 콜백 함수는 프로미스가
rejected상태(reject함수가 호출된 상태)가 되면 호출된다
이 때, 콜백 함수는 프로미스의 에러를 인수로 전달받는다

catch

catch 메서드는 한 개의 콜백 함수를 인수로 전달받는다
catch의 콜백 함수는 프로미스가 rejected상태인 경우만 호출된다
catch메서는 then(undefined, onRejected)와 동일하게 동작한다

finally

finally 메서드는 한 개의 콜백 함수를 인수로 전달받는다
finally 메서드의 콜백 함수는 프로미스의 성공, 실패와 상관없이 무조건 한 번 호출된다


프로미스 체이닝

프로미스 후속 처리 메서드는 언제나 프로미스를 반환하므로
연속적으로 체이닝하여 호출할 수 있다
체이닝을 한 경우 콜백들이 직렬로 처리되므로
모든 콜백 함수의 소요시간+a의 시간이 소요되게 된다


프로미스의 정적 메서드

promise는 5가지 정적 메서드를 제공한다

  • Promise.resolve
    인수로 전달받은 값을 resolve하는 프로미스를 생성
  • Promise.reject
    인수로 전달받은 값을 reject하는 값을 생성
  • Promise.all
    여러 개의 비동기 처리를 모두 병렬 처리할 때 사용, 순서 처리가 보장된다
  • Promise.race
    가장 먼저 fulfilled상태가 된 프로미스의 처리 결과를
    resolve하는 새로운 프로미스를 반환
  • Promise.allSettled
    allSettled메서드가 전달받은 모든 프로미스들의 처리 결과를 반환한다fulfilled상태인 경우 value프로퍼티를,
    rejected상태인 경우 reason 프로퍼티를 갖는다

마이크로태스크 큐

비동기 콜백, 이벤트 핸들러가 test queue에 저장되는 것과 달리
프로미스의 후속 처리 메서드는 microtesk queue에 저장된다
mq는 tq보다 처리 우선 순위가 높으므로
비동기 콜백, 이밴트 핸들러보다 우선적으로 실행된다


fetch

promise기반의 web API이다


async, await

//async
//어떤 함수를 비동기 함수로 만들어주는 키워드
//함수가 프로미스를 반환하도록 변환해주는 키워드
//단 함수 내에서 return으로 프로미스를 반환하는 경우, async는 동작하지 않고 return값을 반환한다.
async function getData() {
  return {
    name: "김정현",
    id: "JH",
  };
}

//await
//async 함수 내부에서만 사용이 가능 한 키워드
//비동기 함수가 다 처리되기를 기다리는 역할
async function printDate() {
  const date = await getData();

  console.log(date);
}

printDate();

콜백, promise, async/await 비교

콜백 형식
const fs = require("fs");

fs.readFile("./readme.txt", (err, data) => {
  if (err) {
    throw err;
  }
  console.log("1번", data.toString());
  fs.readFile("./readme.txt", (err, data) => {
    if (err) {
      throw err;
    }
    console.log("2번", data.toString());
    fs.readFile("./readme.txt", (err, data) => {
      if (err) {
        throw err;
      }
      console.log("3번", data.toString());
    });
  });
});

---
promise 형식
const fs = require("fs").promises;

fs.readFile("./readme.txt")
  .then((data) => {
    console.log("1번", data.toString());
    return fs.readFile("./readme.txt");
  })
  .then((data) => {
    console.log("2번", data.toString());
    return fs.readFile("./readme.txt");
  })
  .then((data) => {
    console.log("3번", data.toString());
    return fs.readFile("./readme.txt");
  })
  .catch((err) => {
    console.error(err);
  });

---
async/await 형식
const fs = require("fs").promises;

async function main() {
  let data = await fs.readFile("./readme.txt");
  console.log("1번", data.toString());
  data = await fs.readFile("./readme.txt");
  console.log("2번", data.toString());
  data = await fs.readFile("./readme.txt");
  console.log("3번", data.toString());
}
main();

//top level await이 추가되면서 async함수로 감싸지 않아도 await이 동작하게 되었다.

profile
개발 공부 블로그

0개의 댓글