TIL 18일차 - Javascript promise, async/await

박찬웅·2023년 2월 23일
0

항해99

목록 보기
23/105

23년 2월 23일

  • 제가 오늘 TIL에서 적는 것은 간략하게 글로만 적었으나, 강의자료를 일부 참고했습니다.

배운 것

오늘은 마지막 심화 이론으로 동기와 비동기를 개념을 간단하게 알고, 그런 다음에 어제 공부했던 콜백을 다시 한번 복습 하였다. 그리고 나서 오늘 중점적으로 공부한 promise, async, await에 대해서 개념부분을 공부하였다.
제가 오늘 TIL에서 적는 것은 아주 간략하게 글만 쓴 내용임을 알립니다.
오늘 배운 강의 자료는 아래의 링크를 참고하면 된다.
promise, async/await 강의 자료

1. 동기와 비동기

동기(Synchronous: 동시에 일어나는)

  • 동기는 말 그대로 동시에 일어난다는 뜻이다. 요청과 그 결과가 동시에 일어난다는 약속이다.
    바로 요청을 하면 시간이 얼마나 걸리던지 요청한 자리에서 결과가 주어져야 한다.
    순서에 맞춰 진행되는 장점이 있지만, 여러 가지 요청을 동시에 처리할 수 없다.
  1. 비동기(Asynchronous: 동시에 일어나지 않는)
  • 비동기는 동시에 일어나지 않는다를 의미한다. 요청과 결과가 동시에 일어나지 않을 거라는 약속이다.
    하나의 요청에 따른 응답을 즉시 처리하지 않아도, 그 대기 시간동안 또 다른 요청에 대해 처리 가능한 방식이다.
    여러 개의 요청을 동시에 처리할 수 있는 장점이 있지만 동기 방식보다 속도가 떨어질 수도 있다.

강의 자료에서는 커피 주문으로 예시를 들었다. 동기의 실생활 예시로 보면 고객이 커피를 주문 하고 난 후 커피가 올 때까지 기다리다 커피가 오면 가져가게 된다. 그리고 다음사람의 주문을 받고 이를 반복하게 된다. 단 이 방식은 모든 사람들이 다 기다려야 하며, 이러면 줄 서서 기다렸던 고객들도 모두 짜증나고 커피를 제조하는 점원도 번거롭기도 하다.
그래서 이걸 반대로 비동기의 실생활 예시로 보면 커피를 주문하고 나고 전동벨을 준다. 그리고 나서 전동벨이 울리면 주문한 커피를 픽업을 한다. 그러면 다음사람도 바로 주문도 계속 서서히 진행 될 것이고 주문한 커피도 픽업 하는 속도도 빠를 것이다.

이걸 토대로 보면 내가 배우는 언어인 자바스크립트는 비동기 방식으로 엔진이 돌아가며, 싱글 스레드 방식으로 구동 된다고 보면 된다. 자바스크립트의 비동기 처리하는 방법은 많지만 몇 가지를 대표적으로 소개 할 것이 이제 하단에 나올 것들이다.

2. promise

promise 객체는 아래와 같은 문법으로 만들 수 있다. promise가 만들어지면 함수는 자동적으로 실행 된다. resolve는 성공해서 결과 도출, reject는 실패해서 에러 호출로 보면 보기 쉽다.

let promise = new Promise(function(resolve, reject) {
  // 프라미스가 만들어지면 executor 함수는 자동으로 실행됩니다.

  // 1초 뒤에 일이 성공적으로 끝났다는 신호가 전달되면서 result는 '완료'가 됩니다.
  setTimeout(() => resolve("완료"), 1000);
});

위 문구는 성공적으로 신호를 보내면 1초 뒤에 resolve를 보내고 '완료'를 출력하게 된다.

let promise = new Promise(function(resolve, reject) {
  // 1초 뒤에 에러와 함께 실행이 종료되었다는 신호를 보냅니다.
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

위 문구는 신호를 보내는 중에 애러가 나타나면 1초 뒤에 reject를 보내고 '에러 발생'을 출력하게 된다.
promise는 resolve와 reject는 둘 중에 하나는 반드시 적용 되어야 한다.

추가적으로 promise 객체는 executor(‘제작 코드’ 혹은 ‘가수’)와 결과나 에러를 받을 소비 함수(‘팬’)를 이어주는 역할을 한다. 소비함수는 .then, .catch, .finally 메서드를 사용해 나타낼 수 있다.

1) then

.then은 프라미스에서 가장 중요하고 기본이 되는 메서드이다. 문법으로는 다음과 같이 나타 낼 수 있다.

promise.then(
  function(result) { /* 결과(result)를 다룹니다 */ },
  function(error) { /* 에러(error)를 다룹니다 */ }
);

2) catch

.catch는 에러만 나타내고 싶을때 사용한다. 문법으로는 다음과 같이 나타 낼 수 있다.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("에러 발생!")), 1000);
});

// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력

3) finally

.finally는 성공·실패 여부와 상관없이 프라미스가 처리되면 바로 실행하게 한다. 문법으로는 다음과 같이 나타 낼 수 있다.

new Promise((resolve, reject) => {
  /* 시간이 걸리는 어떤 일을 수행하고, 그 후 resolve, reject를 호출함 */
})
  // 성공·실패 여부와 상관없이 프라미스가 처리되면 실행됨
  .finally(() => 로딩 인디케이터 중지)
  .then(result => result와 err 보여줌 => error 보여줌)

요약 하면 .then 또는 .catch, .finally의 핸들러(어떤 경우도 상관없음)가 프라미스를 반환하면, 나머지 체인은 프라미스가 처리될 때까지 대기한다. 처리가 완료되면 프라미스의 result(값 또는 에러)가 다음 체인으로 전달된다.

이를 그림으로 나타내면 아래와 같다.

프로미스에서도 여러 API를 사용 할수 있는데 이 중 Promise 클래스에는 5가지 정적 메서드가 있다.

  • Promise.all(promises) – 모든 프로미스가 이행될 때까지 기다렸다가 그 결괏값을 담은 배열을 반환합니다. 주어진 프로미스 중 하나라도 실패하면 Promise.all는 거부되고, 나머지 프라미스의 결과는 무시됩니다.
  • Promise.allSettled(promises) – 최근에 추가된 메서드로 모든 프로미스가 처리될 때까지 기다렸다가 그 결과(객체)를 담은 배열을 반환합니다. 객체엔 다음과 같은 정보가 담깁니다.
    status: "fulfilled" 또는 "rejected"
    value(프로미스가 성공한 경우) 또는 reason(프로미스가 실패한 경우)
  • Promise.race(promises) – 가장 먼저 처리된 프로미스의 결과 또는 에러를 담은 프로미스를 반환합니다.
  • Promise.resolve(value) – 주어진 값을 사용해 이행 상태의 프로미스를 만듭니다.
  • Promise.reject(error) – 주어진 에러를 사용해 거부 상태의 프로미스를 만듭니다.
    실무에선 다섯 메서드 중 Promise.all을 가장 많이 사용합니다.

그외로 콜백을 받는 함수를 프라미스를 반환하는 함수로 바꾸는 것을 '프로미스화(promisification)' 방식도 존재한다.

3. async/await

async와 await라는 특별한 문법을 사용하면 프라미스를 좀 더 편하게 사용할 수 있다. async, await는 놀라울 정도로 이해하기 쉽고 사용법도 어렵지 않다.
async 키워드부터 알아보면 async는 function 앞에 위치한다. 문법적으로 표현하면 다음과 같이 나타 낼 수 있다.

async function f() {
  return 1;
}

async가 붙은 함수는 반드시 프로미스를 반환하고, 프로미스가 아닌 것은 프로미스로 감싸 반환된다.

async안에다 await를 사용 할 수 있는데 await 문법은 다음과 같다.

// await는 async 함수 안에서만 동작합니다.
let value = await promise;

자바스크립트는 await 키워드를 만나면 프로미스가 처리될 때까지 기다린다. 결과는 그 이후 반환됩니다. 참고로 await는 일반 함수에서는 사용 못한다. async 안에서만 사용이 가능하다.

간단하게 요약하면 다음과 같다.
function 앞에 async 키워드를 추가하면 두 가지 효과가 있다.

  1. 함수는 언제나 프로미스를 반환하고
  2. 함수 안에서 await를 사용할 수 있다.

프로미스 앞에 await 키워드를 붙이면 자바스크립트는 프로미스가 처리될 때까지 대기하며, 처리가 완료되면 조건에 따라 아래와 같은 동작이 이어진다.

  1. 에러 발생 – 예외가 생성됨(에러가 발생한 장소에서 throw error를 호출한 것과 동일함)
  2. 에러 미발생 – 프로미스 객체의 result 값을 반환
    async/await를 함께 사용하면 읽고, 쓰기 쉬운 비동기 코드를 작성할 수 있다.

async/await를 사용하면 promise.then/catch가 거의 필요 없다. 하지만 가끔 가장 바깥 스코프에서 비동기 처리가 필요할 때같이 promise.then/catch를 써야만 하는 경우가 생기기 때문에 async/await가 프로미스를 기반으로 한다는 사실을 알고 있어야 한다. 여러 작업이 있고, 이 작업들이 모두 완료될 때까지 기다리려면 Promise.all을 활용할 수 있다는 점도 알고 있어야 한 다는 점도 알아야 한다.

알게 된 점

오늘도 만만하게 어려웠었다. 앞에 이틀과 달리 코어 자바스크립트에서는 없는 내용이라 다시 이전대로 강의 노트를 보고 공부를 하였다. 드림코딩 유튜브 영상을 한번 보고 개념을 들어다 보니까 그나마 이해하는데는 도움이 되었다. 어제 콜백 부분을 좀 공부를 하고 진입을 했다면 그나마 좀 할만은 했다. 다만 오늘 같은 경우에는 예제 코드를 보면서 이해 하면서 공부를 하긴 했는데, 이게 만만치 않아서 이해하는데 상당히 오래 걸렸다. 개념은 쉬웠는데 실제로 코드 예시로 보니까 엄청 어려웠던것 같다.
지난 3일동안 심화적인 이론을 배웠지만 나중에 면접에서도 나오는 질문들이라고 하기는 하는데, 지금 당장은 많은 것들은 이해하지는 못했다. 그래서 공부하는데 가장 힘들었고 시간도 잘 안지나간것 같다. 나중에 주특기 배우고 프로젝트 하다보면 이게 왜 필요한지 이해를 하게 된다고는 한데, 아직은 나한테 완벽하게 왜 배우는지는 오리무중 상태로 끝난것 같아서 아쉬웠다. 그래도 시간되면 틈틈히 복습은 해 볼 생각이다.

앞으로 할 일

오늘을 끝으로 javascript의 문법은 완전히 종료된다. 이제 내일부터는 주특기인 node.js를 배우게 된다. 총 3주동안 진행하는데 계속해서 이론이나 실습공부라고 하니 더 열심히 해봐야겠다. 팀원들이 또 바뀔 예정이라고 하는데 새로운 분들과도 잘 어울리길 기원한다.

profile
향해 13기 node.js 백앤드

0개의 댓글