동기/비동기, async/await/promise

the Other Object·2023년 3월 6일
0

동기

1. 직렬적으로 태스크를 수행하는 방식이다.
2. 요청을 보낸 후 응답을 받아야 다음 동작 이루어짐
3. 어떤 태스크를 처리할 동안 나머지 태스크는 대기한다.
4. 실제로 cpu가 느려지는 것은 아니지만 시스템의 전체적인 효율 저하

비동기

1. 병렬적으로 태스크를 수행
2. 요청 보낸 후 응답여부와 상관없이 다음 태스크가 동작, 효율적 자원 사용가능
3. 비동기요청시 응답 후 처리할 '콜백함수'를 함께 알려주고, 따라서 해당 태스크가 완료되었을 때 '콜백함수'가 호출된다.

Promise

* 자바스크립트는 비동기처리를 위한 하나의 패턴으로 콜백함수를 사용한다. 하지만 전통적 콜백패턴 : 콜백헬, 가독성 나쁨, 비동기처리 중 발생한 에러처리 및 여러개의 비동기처리를 한번에 처리하기 어려움
* 그래서 `Promise` 라는 비동기처리를 위한 또 다른 패턴을 도입
* `Promise` : 전통적 콜백패턴이 가진 단점 보완, 비동기처리 시점을 명확하게 표현할 수 있다는 장점이 있다.
* `Propmise``Promise 생성자함수`를 통해 인스턴스화한다, Promise생성자함수는 비동기 작업을 수행할 콜백함수를 인자로 전달받는데 이 콜백함수는 resolve와 reject함수를 인자로 전달받는다.

//Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  
  //비동기작업을 수행한다.
  if () {
   resolve('result')
  }
  else {
   reject('failure reason')
  }
})

//promise는 비동기처리가 성공/실패했는지 등의 상태(state)정보를 가진다.
* pending : 비동기처리가 아직 수행되지 않은 상태
* fulfilled : (성공) 비동기처리 수행된 상태
* rejected : (실패) 비동기처리 수행된 상태
* settled : (성공 또는 실패) 비동기처리 수행된 상태

Promise의 후속처리 메소드 (then, catch)

::: 비동기함수 내에서 Promise객체를 생성하고 내부에서 비동기처리를 구현한다.
::: 이 때, 비동기처리에 성공하면 resolve 메소드를 호출,
::: 이 때, resolve메소드의 인자로 비동기처리결과를 전달하는데, 이 처리결과는 Promise객체의 후속처리 메소드로 전달된다.
::: 만약, 비동기처리에 실패하면 : reject 메소드를 호출,
::: 이 때, reject메소드의 인자로 에러 메시지를 전달한다. 이 에러 메시지는 Promise 객체의 후속처리 메소드로 전달된다.

then

  • then 메소드는 두개의 콜백함수를 인자로 전달받는다.
    첫번째 콜백함수 = 성공(fullfilled, resolve함수가 호출된 상태) 시 호출된다.
    두번째 콜백함수 = 실패(rejected, reject함수가 호출된 상태) 시 호출된다.
    then 메소드는 Promise를 반환한다.

catch

  • 예외가 발생하면(비동기처리에서 발생한 에러와 then메소드에서 발생한 에러) 호출된다. catch메소드는 Promise를 반환한다.

Promise 체이닝

::: 비동기함수의 처리결과를 가지고 다른 비동기함수를 호출 해야하는 경우, 함수의 호출이 중첩되어 복잡도가 높아진다 === 콜백헬 발생
::: Promise는 후속처리메소드인 then 이나 catch 로 메소드를 체이닝(chainning)하여 여러개의 프로미스를 연결하여 사용해서 콜백헬을 해결한다.
::: 따라서, then메소드가 Promise객체를 반환하도록 하면 여러개의 프로미스를 연결하여 사용가능 (then 메소드는 기본적으로 Promise를 반환)

async/await

  • async와 await는 기존의 비동기처리방식인 콜백함수와 Promise의 단점을 보완, 가독성 높혀준다
//async와 await 기본문법

async function 함수명() {
  await 비동기처리메소드명();
}
  • async키워드는 function 앞에 사용한다.
  • function 앞에 async를 붙이면 해당 함수는 항상 Promise를 반환한다.
  • Promise가 아닌 값을 반환하더라도 이행상태의 프라미스(Resolved Promise)로 값을 감싸 이행된 프라미스가 반환되도록 한다.
//아래 예시함수를 호출하면 result가 '1'인 이행프라미스가 반환된다.

async function f() {
  return 1;
}
f().then(alert);

//위 함수에서 1을 Promise.resolve로 감싸도 같은결과 반환

async function f() {
  return Promise.resolve(1);
}
f().then(alert);


*, async가 붙은 함수는 반드시 프라미스를 반환하고 프라미스가 아닌 것은 프라미스로 감싸서 반환한다.
  • await는 async함수 안에서만 동작한다. await는 Promise가 처리 될 때까지 기다리는역할을 하고, 결과는 그 이후에 반환된다.

async function f() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('완료'), 1000)
  });
  
  //프라미스가 이행 될 때까지 기다림
  let result = await promise;
  alert(result);
}

f();
  • 함수를 호출하고, 함수 본문이 실행되는 도중에 let result = await promise;라인에서 실행이 잠시 '중단'되었다가 프라미스가 처리되면 실행이 재개된다.
  • 이 때, 프라미스 객체의 result값이 변수 result에 할당된다.
  • 따라서, 위 예시를 실행하면 1초 뒤에 '완료'가 출력된다.
  • await === promise가 처리 될 때까지 함수실행을 기다리게 만든다.
  • 프라미스가 처리되면 그 결과와 함께 실행이 재개되며, 프라미스가 처리되길 기다리는 동안엔
  • 엔진이 다른 일(다른 스크립트를 실행, 이벤트 처리 등등)을 할 수 있기 때문에 cpu리소스가 낭비되지 않는다.
  • await를 사용하지 않았다면 데이터를 받아 온 시점에 콘솔을 출력할 수 있게 콜백함수나 .then() 등을 사용해야 한다.
  • 하지만 async/await 문법 덕에 비동기에 대한 사고를 하지 않아도 된다.
  • 또한, awaitpromise.then 보다 좀더 세련되게 프라미스의 result값을 얻을 수 있다. promise.then보다 가독성 좋고 쓰기 쉬움

async/await 에러제어

  • await가 던진 에러는 throw가 던진 에러를 잡을떄처럼 try..catch 를 사용해서 잡을 수 있다.
  • 에러가 발생하면 제어흐름이 catch 블록으로 넘어간다. 또한, 여러 줄의 코드를 try로 감쌀 수 있다.
async function f() {
  try {
    let response = await fetch('http://유효_하지_않은_주소');
  } catch(err) {
    //type Error: failed to fetch
    alert(err); 
  }
}
f();
  • async/await을 사용하면 await가 대기를 처리해주기 때문에 .then이 거의 필요하지 않다.
  • .catch 대신 일반 try..catch를 사용할 수 있다.
  • 하지만, 문법제약 때문에 async함수 바깥의 최상위레벨 코드에서는 await를 사용할 수 없다.
  • 그렇기 때문에 관행처럼 .then/catch를 추가해 최종결과나 처리되지 못한 에러를 다룬다.

0개의 댓글