모던 자바스크립트 복습 #3

벨로퍼트와 함께하는 모던 자바스크립트
React로 넘어가기 전에 빠르게 JavaScript를 복습해본다.

3장 자바스크립트에서 비동기 처리 다루기

동기적 처리와 비동기적 처리에 대해 알아보자.

특정 함수가 끝난 다음에 어떤 작업을 처리하고 싶다면 callback함수를 파라미터로 전달해주면 된다.
✔️ callback 함수란 함수 타입의 값을 파라미터로 넘겨줘서, 파라미터로 받은 함수를 특정 작업이 끝나고 호출을 해주는 것이다.

function work(callback){
  specificFunction(() => {
    ...
    callback();
  });
}

console.log('작업 시작!');			// 1
work(() => {					   // 3
  console.log('작업이 끝났어요!')	  // 4
});
console.log('다음 작업');			// 2

비동기 작업을 다룰 때에는 callback 함수 외에도 Promise, 그리고 async/await 라는 문법을 사용하여 처리 할 수 있습니다.

01. Promise

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

iap(0, n => {
  iap (n, n => {
    iap (n, n => {
      console.log("끝");
    });
  });
});

결과는 순차대로 나온다. 비동기적으로 처리해야 하는 일이 많아질수록 코드의 깊이는 계속 깊어진다. Promise를 통해 코드의 깊이가 깊어지는 현상을 방지할 수 있다.

Promise 만들기

const myPromise = new Promise((resolve, reject) => {
  // 구현...
})

성공하면 resolve를, 실패하면 reject를 호출하면 된다.
가장 기본적인 틀은 다음과 같다.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  },1000);
});

myPromise
  .then(res => {console.log(res);})
  .catch(err => {console.log(err);});

응용하면 다음과 같다.

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

increaseNprint(0)
  .then(n => {
    return increaseNprint(n);
  })
  .then(n => {
    return increaseNprint(n);
  })
  .catch(e => {
    console.error(e);
  });

아래에서 increaseNprint에 항상 (n)을 넣어주지 않아도 .then(increaseNprint)을 통해 코드를 쓰면 then에서 알아서 n을 전달해주므로 코드를 짧게 할 수 있다.

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

Promise를 사용하면 비동기 작업의 개수가 많아져도 코드의 깊이가 깊어지지 않게 된다.

02. async/await

async/await는 ES8에 해당하는 문법으로 Promise를 더욱 쉽게 사용할 수 있도록 함.

function sleep(ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process(){
  console.log('안녕');
  await sleep(1000);
  console.log("반갑");
}

process().then(()=> console.log("끝"));

async/await 문법을 사용할 때에는, 함수를 선언할 때 함수 앞부분에 async 키워드를 붙이고 Promise 앞부분에 await를 넣어주면 해당 Promise가 끝날 때까지 기다렸다가 다음 작업을 수행한다.

함수에서 async를 사용한다면 해당 함수는 결괏값으로 Promise를 반환한다.

function sleep(ms){
  return new Promise(res => setTimeout(res,ms));
}

const getDog = async () => {
  await sleep(1000);
  return "멍멍이";
}

async function process(){
  const dog = await getDog();
  console.log(dog);
  
  const dog2 = await getDog();
  console.log(dog);
}
  
process();
async function process(){
  const result = await Promise.all([getDog(), getDog()]);
  console.log(result);
}

process(); //(2) ["멍멍이", "멍멍이"]
async function process(){
const [dog1, dog2, dog3] = await Promise.all([getDog(), getDog(), getDog()]);
  console.log(dog1);
}

process();

✔️ Promise.all을 사용할 때에는 등록한 Promise 중에 하나라도 실패하면 모든게 실패한 것으로 간주한다.

✔️ Promise.race는 여러개의 Promise를 등록해서 실행했을 때 가장 빨리 끝난 것 하나만의 결과를 가져온다.

Promise.race로 인해 결과를 얻었다면 뒤늦게 나온 결과에서 error가 발생하여도 무시된다.

좋은 웹페이지 즐겨찾기