반응형
250x250
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

짧은코딩

async/await, Promise로 바꾸기 본문

JS/인간 JS엔진

async/await, Promise로 바꾸기

5_hyun 2024. 1. 28. 23:52

then, catch 반복하기 === try, catch 분리하기

Promise

- catch는 앞부분을 다 책임진다!

const p = new Promise(
  // 여기부터
  (resolve, reject) => {
    console.log("제일 먼저");
    setTimeout(() => {
      a = 5;
      console.log(a);
      resolve(a);
    }, 0);
  }
  //  여기까지 동기
);

console.log("딴짓");

p.then((result) => {
  console.log("result", result);
})
  .then(() => {
    //여기서 에러나면
  })
  .then(() => {})
  .then(() => {})
  .catch(() => {
    // 나머지 then 다 건너 뛰고 여기로 이동
  })
  .finally(() => {});
  • catch는 앞의 전체에 대한 catch

-catch를 여러 개 사용

const p = new Promise(
  // 여기부터
  (resolve, reject) => {
    console.log("제일 먼저");
    setTimeout(() => {
      a = 5;
      console.log(a);
      resolve(a);
    }, 0);
  }
  //  여기까지 동기
);

console.log("딴짓");

p.then((result) => {
  console.log("result", result);
})
  .then(() => {
    //여기서 에러나면
    console.log(2);
  })
  .catch(() => {})
  .then(() => {
    return Promise.reject(1);
  })
  .catch(() => {
    console.log("에러 처리");
  })
  .then(() => {
    console.log("에러 처리 후");
  })
  .catch(() => {
  })
  .finally(() => {});

  • then, catch 계속 반복해도 됨
  • catch는 자신의 앞에서 에러가 발생하면 실행됨
  • catch를 특정 then에 대한 에러 처리만 할 수 있도록 할 수 있다.

async/await

-분리 전

// setTimeout을 Promise로 만드는 법
function delayP(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
  });
}

async function a() {
  try {
    await delayP(1000);
    await delayP(1000);
    await delayP(1000);
    await delayP(1000);
  } catch (error) {
    console.error(error);
  }
}

 

-분리 후

// setTimeout을 Promise로 만드는 법
function delayP(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
    reject(err); // 에러나면 에러 처리
  });
}

async function a() {
  try {
    await delayP(1000);
  } catch (error) {
    console.error(error);
  }
  try {
    await delayP(1000);
    await delayP(1000);
    await delayP(1000);
  } catch (error) {
    console.error(error);
  }
}
  • 이렇게 try, catch로 분리하면 에러 처리를 따로 할 수 있다.
  • 위에서 사용한 Promise에서 then, catch를 연달아서 사용한 것과 같은 의미이다.

대입 방식

Promise

-then의 Promise가 아닌 return 값

const p = new Promise(
  // 여기부터
  (resolve, reject) => {
    console.log("제일 먼저");
    setTimeout(() => {
      a = 5;
      console.log(a);
      resolve(a);
    }, 0);
  }
  //  여기까지 동기
);

console.log("딴짓");

p.then((result) => {
  console.log("result", result);
  return 1;
})
  .then((result) => {
    console.log(result); // 1
    // 함수는 아무것도 안적으면 기본적으로 return undefined
  })
  .then((result) => {
    console.log(result); // undefined
  })
  .catch(() => {})
  .finally(() => {});
  • p의 첫 번째 then에서 return 1을 하면, 다음 then의 result는 1이 됨
  • 두 번째 then에서 return을 안 하면, 다음 then의 result는 undefined
    • 함수는 아무것도 안 하면 기본적으로 return undefined;

-then의 Promise인 return 값

const p = new Promise(
  // 여기부터
  (resolve, reject) => {
    console.log("제일 먼저");
    setTimeout(() => {
      a = 5;
      console.log(a);
      resolve(a);
    }, 0);
  }
  //  여기까지 동기
);

console.log("딴짓");

p.then((result) => {
  console.log("result", result);
  return Promise.resolve(1);
})
  .then((result) => {
    // Promise를 return하면 Promise를 resolve한 값이 리턴됨
    console.log(result);
    // 함수는 아무것도 안적으로 기본적으로 return undefined
  })
  .then((result) => {
    console.log(result); // undefined
  })
  .catch(() => {})
  .finally(() => {});
  • 만약 then에서 Promise를 return 하면, 다음 then에서는 Promise의 resolve()된 값이 리턴됨

async/await

async function a() {
  const a = await 1;
  const b = await Promise.resolve(1);
}
  • aync/await에서도 그냥 값을 넘겨주면 a에 1이 들어가고, Promise를 넘겨주면 b에 Promise의 resolve() 값이 들어감
  • await은 "왼쪽 <- 오른쪽"으로 진행됨

async/await을 Promise로 바꾸기

async/await

async function a() {
  const a = await 1;
  console.log("a", a);
  console.log("hmm");
  await null;
  const b = await Promise.resolve(1);
  console.log("b", b);
  return b;
}

 

async/await 코드를 Promise로 바꾸기

Promise.resolve(1)
  .then((a) => {
    console.log("a", a);
    console.log("hmm");
    return null;
  })
  .then(() => {
    return Promise.resolve(1);
  })
  .then((b) => {
    console.log("b", b);
    return b;
  });
  • await을 기준으로 바꿔야 한다.
    • await를 then으로 생각하자, await은 "왼쪽 <- 오른쪽", promise에서는 "왼쪽 -> 오른쪽"
    • await이 3개 있으니까, then도 3개가 나오게 된다.
  • 맨 처음 const a = await 1;은 Promise가 아닌 값이라 Promise.resolve(1)로 해준다.
    • Promise화를 시켜야 then을 붙일 수 있다.
    • 만약 const a = axios.get();이면 Promise니까 그대로 axios.get()을 써주면 된다.
  • 첫 번째 then
    • await과 await 사이에 있는 console들을 다 넣어줬다.
    • 그리고 다음 await은 null이니까 return null을 해준다.
  • 두 번째 then
    • 대입하는 게 없으니까 매개변수 부분이 없어도 된다.
    • 다음 await이 Promise.resolve(1)이니까 return Promise.resolve(1)을 해준다.
  • 마지막 then
    • b를 받아주고, console.log('b', b)를 추가해 주면 된다.
    • async/await에 return b가 있으니까 return b를 해주면 된다.
  • 사실 async/await과 Promise는 1대1로 대응되는 관계가 아니다.
    • 이 코드에서는 되지만, 만약 마지막 줄이 return a + b;이라면
    • 마지막 then에서 스코프 체인에 의해 a에 접근하지 못하여 애매해진다.
    • 이땐 첫 번째 then부터 마지막 then까지 a를 인자로 넘겨주면 해결할 수 있다.

바뀐 Promise를 분석해 보기

async function a() {
  console.log("2");
  const a = await 1;
  console.log("4");
  console.log("a", a);
  console.log("hmm");
  await null;
  const b = await Promise.resolve(1);
  console.log("b", b);
  return a + b;
}

console.log("1");
a()
  .then((result) => {
    console.log(result);
  })
  .then((result2) => {
    console.log(result2);
  });
console.log("3");

 

-결과

 

-분석

  1. 우선 처음에 console.log("1") 실행
  2. a() 호출
    • 함수 a에서도 동기인 부분이 존재한다.
      • 첫 번째 await의 위에 부분까지는 동기 부분이다.
      • 첫 번째 await 직전까지만 실행이 되고, 첫 번째 await에서부턴 다 비동기여서 백그라운드로 넘어간다.
    • 함수 a의 동기 부분만 실행이 되면 a는 호출이 종료된다.
  3. console.log(3)까지 실행하면 호출 스택은 빈다.
  4. 비동기 실행을 위해 백그라운드로 넘어감
    • 백그라운드에는 await, await, await, then, then이 순서대로 쌓여있음 
    • Promise가 아닌건 자동으로 Promise.resolve()가 붙여지고 Promise는 resolve() 되니까, 태스크 큐의 마이크로(m)로 하나씩 이동
    • 위에서 하나씩 실행되면, 이벤트 루프가 호출 스택이 빈 것을 확인하고 태스크 큐의 마이크로(m)에 있는 함수를 호출 스택에 올림
    • then((result)=>{})에서 result는 함수 a의 반환값인 2이고, console.log(2) 실행
    • then((result2)=>{})에서 result2는 undefined라서 undefined 출력
  5. 호출 스택, 백그라운드, 태스크 큐가 다 비고 JS 실행 종료

-출처

https://www.youtube.com/watch?v=1DGAyl4kxhY&list=PLcqDmjxt30Rt9wmSlw1u6sBYr-aZmpNB3&index=15

 

728x90
반응형

'JS > 인간 JS엔진' 카테고리의 다른 글

클로저  (1) 2024.01.30
await 연달아쓰면 Promise.allSettled를 생각해보자  (0) 2024.01.29
Promise에도 동기는 있다!  (0) 2024.01.27
비동기는 동시가 아니다  (1) 2024.01.27
Promise, async/await  (2) 2024.01.25
Comments