TIL 7주차 비동기 제어 promise async/await

6587 단어 TILTIL

📌 동기 / 비동기

자바스크립트의 경우에는 Single Thread 언어이기 때문에, 하나의 스레드에서 작업들이 순차적으로 수행된다. 동기적인 실행은 한 줄의 코드가 완료될 때까지 뒤의 코드가 실행되지 못하는 현상이 발생한다.

이때, setTimeout()와 같은 Web API로 비동기로 동작하게 할 수 있다. 비동기는 특정 코드의 처리가 끝나기 전에 다음 코드를 실행할 수 있는 것이다.

하지만, 만약 비동기적으로 동작하지만, 순서가 중요하다면 어떻게 해야할까?
비동기 처리는 결과를 예측할 수 없기 때문에 동기식의 처리가 필요하다.

이때, 콜백, promise, async/await를 통해 비동기 동작을 조작하면 된다. 즉 순차적으로 실행될 수 있는 비동기 처리를 하는 것이다.


📌콜백

test 함수가 실행 된 후 callback 함수가 실행된다.

const test = function (value, callback) {
  console.log(value);
  callback();
};

test('before', function () {
  console.log('callback');
});

// before
// callback

📌Promise

const promise = new Promise((resolve, reject) => ~~)

new Promise 생성자가 반환하는 객체는 state와 result를 프로퍼티를 갖는다.

📎resolve

resolve 는 비동기 처리 성공 시 호출

const pr = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('ok');
  }, 2000);
});

pr.then((result) => {
  console.log(result);
})
  .catch((err) => {
    console.log(err);
  })
  .finally(() => {
    console.log('end');
  });

📎reject & catch 에러 처리

reject는 비동기 처리 실패시 호출

  • catch : reject인 경우에만 실행, catch로 구분해서 작성하는 것이 가독성 좋음.
  • finally : resolve, reject 상관없이 이행이 완료되면 실행.
    로딩 화면을 제거할 때 사용 가능.
const pr2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('err......'));
  }, 3000);
});

pr2
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err);
  })
  .finally(() => {
    console.log('end');
  });
  
//결과
//Error: err......
//end 
  • resolve이면 then으로 찾아간다.
  • reject을 리턴받게 되면, catch를 찾아간다.
  • catch 실행 후, 다음 then이 있다면 then을 실행한다.

📎promise chaining

프로미스는 여러 개의 프로미스를 연결하여 사용할 수 있다.
then() 메서드를 호출하고 나면 새로운 프로미스 객체가 반환한다.

<참고 예제 코드>

const f1 = (message) => {
  console.log(message);
  return new Promise((res, rej) => {
    setTimeout(() => {
      res('1번 주문');
    }, 3000);
  });
};
>
const f2 = (message) => {
  console.log('2번', message); // 2번 1번 주문
  return new Promise((res, rej) => {
    setTimeout(() => {
      res('2번 주문');
    }, 1000);
  });
};
>
const f3 = (message) => {
  console.log('3번', message); //3번 2번 주문
  return new Promise((res, rej) => {
    setTimeout(() => {
      res('3번 주문');
    }, 2000);
  });
};

promise chaining

console.time('x');
f1()
  .then((res) => f2(res))
  .then((res) => f3(res))
  .then((res) => console.log(res)) // 3번 주문
  .catch(console.log)
  .finally(() => {
    console.log('end');
    console.timeEnd('x'); 
    // 순차적으로 실행되기 때문에 대략 6초가 걸린다.
  });

콜백 지옥

f1(function () {
  f2(function () {
    f3(function () {
      console.log('end');
    });
  });
});

📌async/await

예시 코드로 await 정리, MicroTakse Queue

비동기 처리 메서드가 프로미스 객체를 반환해야 await가 의도한 대로 동작한다.
하지만, 일반 함수를 리턴받아도 작동하기는 한다.

📎async

async를 쓸 경우 promise를 쓰지 않아도 자동적으로 promise를 반환한다.
promise를 반환하기 때문에 then을 사용할 수 있다.

async function fetchUser(){
  return 'async!!'
}

const user = fetchUser()
user.then(console.log) // Promise {<fulfilled> :"async!!"}

async를 함수 앞에 쓰게 되면 자동적으로 프로미스를 반환한다.

📎await

비동기로 처리되는 부분 앞에 await를 붙여준다.

await 문의 반환값은 Promise 에서 fulfill된 값
Promise가 reject되면, await 문은 reject된 값을 throw

여러 await는 앞의 await이 끝나기 전까지 다음으로 넘어가지 않는다.
예를 들면 f1(1000), f2(2000), f3(1000)로 아래와 같이 실행한다면 총 4000ms가 소요된다.

이를 해결하기 위해 Promise.all과 같은 프로미스 메소드를 사용할 수 있다.(Promise 메소드 정리)

async function order() {
  const result1 = await f1();
  const result2 = await f2(result1);
  const result3 = await f3(result2);
  return result3;
}

order()
  .then((v) => console.log(v));
  .finally(() => console.log('end'))

async는 await와 함께 쓸 때 비동기적으로 작동한다.

async function start() {
  console.log(11);

  const prom = new Promise((resolve) => {
    console.log('promise1');
    resolve('1');
  });

  const prom2 = new Promise((resolve) => {
    console.log('promise2');
    resolve('2');
  });

  let a = await prom;
  let b = await prom2;

  console.log(2);
}

start();
console.log(3);

//11
//promise1
//promise2
//3
//2

async만 쓰인 아래 예시로 동기적으로 동작하는 것을 확인 할 수 있다.
(즉, async는 await과 같이 사용해야 비동기적으로 실행된다.)

async function start() {
  console.log(11);
  console.log(2);
}

start();
console.log(3);

//11
//2
//3

📎try / catch 에러 처리

async는 try, catch를 통해 에러 처리가 가능하다.

async function order() {
  try {
    const result1 = await f1();
    const result2 = await f2(result1);
    const result3 = await f3(result2);
    console.log(result3);
  } catch (e) {
    console.log(e);
  }
  console.log('end');
}

order();

📌Promise 메소드

Promise.all
Promise.race
Promise 메소드 정리


참고)
코딩앙마 프로미스
비동기 콜백, promise, async 정리 블로그
인터뷰 대비 Rromise

좋은 웹페이지 즐겨찾기