Post

비동기 처리





Javascript의 비동기 처리

  • 자바스크립트는 특정 코드를 비동기 처리한다.
    • 어떤 코드의 연산이 끝날 때까지 기다리지 않고,
    • 다음 코드를 먼저 실행해버린다.
    • 파일 처리나 데이터 페칭 등이 있다.
  • 브라우저 위에서 돌아간다는 자바스크립트의 특징 때문에 오래 걸리는 작업을 기다려줄 수 없다.
    • 서버의 요청을 받아 화면에 띄워주는 역할을 하기 때문에
    • 하나하나 다 기다려줄 수는 없다.
    • 받아오면 그때 띄우고를 반복해 빠르게 화면을 구성하는 것이다.


1
2
3
4
5
6
7
8
9
10
11
sendMessage=()=>{
  console.log('팀장님 인생');

  setTimeout(()=>{
    console.log('최고라던  가게');
  },3000);

  console.log('망했어요.');
};

sendMessage();
  • 자바스크립트가 비동기라는걸 모르는 나같은 사람들은
    • 팀장님 인생
    • (약 3초 뒤)
    • 최고라던 그 가게
    • 망했어요.
    • 이 순서를 생각할 것이다.
  • 그러나 setTimeout이 3초를 기다리는 동안 훅 지나가 뒤에 코드를 먼저 실행한다.
    • 팀장님 인생
    • 망했어요.
    • (약 3초 뒤)
    • 최고라던 그 가게





콜백 함수

  • 위의 비동기를 잡을 수 있는 방법으로 콜백 함수가 있다.
  • 콜백 함수란,
    • 특정 메서드가 끝나면 실행시켜주세요 하는 함수이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
sendMessage=(end)=>{
  console.log('팀장님 인생');

  setTimeout(()=>{
    console.log('최고라던  가게');
    end();
  },3000);

};

sendMessage(()=>{
  console.log('망했어요.')
});
  • sendMessage를 호출할 때 마지막 메시지를 띄우는 콜백 함수를 넘겨준다.
  • sendMessage 내부에서 콜백 함수를 호출해서 예상되는 결과를 얻을 수 있었다.
    • 팀장님 인생
    • (약 3초 뒤)
    • 최고라던 그 가게
    • 망했어요.
  • 그러나 프로그램을 짜다보면 코드는 점점 더 복잡해질 수 밖에 없고,
  • 비동기 처리가 겹겹으로 필요한 경우가 생긴다.
  • 그때마다 콜백 함수를 처리해주면 indent가 자꾸 늘어나고
  • 코드가 복잡해지게 된다. 이것을 콜백 지옥이라고 하더라.





Promise

  • Promise 역시 비동기 처리를 위한 객체이다.
  • Promise에는 세 가지 상태가 있다.
    • Pending
      • 비동기 로직 처리가 끝나길 기다리는 상태
    • Fulfilled
      • 비동기 로직 처리가 끝나고 결과 값을 반환한 상태
    • Rejected
      • 비동기 로직 처리 중에 오류가 발생한 상태


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sendMessage=(end)=>{
  console.log('팀장님 인생');

  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log('최고라던  가게');
      resolve(); // 얘가 실행되면 아래의 then()이 호출됨.
    },3000);
  });
};

sendMessage()
  .then(res=>{ // res는 Promise의 결과 값.
    console.log("망했어요.");
  });


  • 생성이 완료된 Promise는 처음엔 Pending 상태이다.
  • resolve()가 호출되는 시점에 Fulfilled가 된다.
  • reject()가 호출되는 시점에 Rejected가 된다.
    • 이 경우는 then()이 아닌 catch()로 받을 수 있다.





async, await

  • 얘네 역시 비동기 처리를 위한 문법이다.
  • 프라미스를 좀 더 편하게 사용할 수 있다.
  • async는 함수 앞에 위치한다.
    • async가 붙은 함수는 항상 이행된(fulfilled) Promise 객체를 리턴한다.
    • 만약 async가 아닌 리턴 값을 가진다고 해도, fulfilled Promise로 감싸서 리턴한다.
  • await은 async가 붙은 함수 내에서만 사용이 가능하다.
    • await 키워드는 비동기 처리가 끝날 때 까지 기다린다.
    • await이 붙은 프라미스 처리가 끝나면 그 뒤의 코드가 동작한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
async function sendMessage() {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('최고라던 그 가게');
    }, 3000);
  });

  console.log('팀장님 인생');
  console.log(await promise);
  console.log('망했어요.');
}

  • 내가 원하던 결과가 나온다.
    • 팀장님 인생
    • (약 3초 대기)
    • 최고라던 그 가게
    • 망했어요.
  • await 키워드를 만나면 처리가 끝날 때까지 기다리기 때문에 원하던 결과를 얻을 수 있었다.
  • 이행된 프라미스를 받기 때문에 깔끔한 코드를 작성할 수 있다.



에러 핸들링

  • await가 붙은 프라미스는 에러가 발생하면 throw한다.
    • 예를 들어,
    • await Promise.reject(new Error(‘error’)); 는
    • throw new Error(‘error’) 와 같다.
  • 이 경우 역시 try/catch 문으로 에러를 잡아줘야 한다.
  • 만약 에러를 잡아주지 않으면 rejected Promise를 리턴한다.
    • 이런 경우 프라미스 에러가 발생한다.
    • .catch() 메서드로 에러를 잡아줄 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// try/catch로 잡는 방법
async function error1() {
    try {
        await Promise.reject(new Error('error111'));
    } catch(e) {
        console.log(e.message);
    }
}

error1(); // error111

async function error2() {
    await Promise.reject(new Error('error222'));
}

// 에러를 잡지 않은 경우.
error2(); // Uncaught Error

// catch()로 에러를 잡은 경우.
error2()
  .catch(err => console.log(err.message)); // error222





This post is licensed under CC BY 4.0 by the author.