2021_04_26

TIL - Asynchronous & Promise

1. Asynchronous & Promise

Asynchronous 즉, 비동기는 프로그램이 어떤 task를 실행할 때 동시에 다른 task를 실행할 수 있는 것이다. 실생활에서 많이 접할 수 있는 인터넷 로딩 창, 백그라운드 실행 등이 비동기 작업에 해당한다.

const printString = (string) => {
    setTimeout(
      () => {
        console.log(string)
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  }
  const printAll = () => {
    printString("A")
    printString("B")
    printString("C")
  }
  printAll()

이와 같이 비동기적으로 프로그램을 작성하면 콘솔에 찍히는 순서가 매번 다르게 나온다. 즉, 우리가 task의 순서를 제어할 수 없다. 만약 우리가 직접 순서를 제어하고 싶을 때에는 어떻게 해야할까? 이럴 때 callback을 사용한다.

callback을 배우기 전에 우리는 콜백함수가 실행되는 순서를 알아야한다.

  1. 비동기 요청과 함께 콜백함수를 전달한다.
  2. 비동기 요청이 처리된다.
  3. 전달한 콜백 함수가 실행된다.

이 사실을 기억하고 callback에 대해 알아보자.!!

1. callback

const printString = (string, callback) => {
    setTimeout( //일정 시간 뒤에 실행한다.
      () => {
        console.log(string)
        callback() //callback을 실행한다.
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  }
   const printAll = () => {
    printString("A", () => { //A가 실행된다.
      printString("B", () => { // A가 실행된 후 B를 실행한다.
        printString("C", () => {}) //A, B가 실행된 후 C를 실행한다.
      })
    })
  }
  printAll()

callback을 실행시킴으로써 작업이 동시에 실행되지 않고 순서대로 실행된다. 해당 코드를 실행시키면 콘솔에 A, B, C 순서대로 출력되는 것을 볼 수 있다.

그러나 A B C 3번만 실행시켜도 이렇게 코드가 길어지고, 가독성이 떨어지는데 10개 20개를 실행하려면 엄청나게 긴 코드가 필요할 것이다. 이러한 현상을 callback hell이라고 부른다.

그래서 조금 더 코드를 가독성있게 작성하기 위해 'promise'라는 개념이 등장하였다.

2. promise

const printString = (string) => {
    return new Promise((resolve, reject) => {
      setTimeout( //일정 시간 뒤에 실행한다.
        () => {
         console.log(string)
         resolve()
        }, 
        Math.floor(Math.random() * 100) + 1
      )
    })
  }
  const printAll = () => {
    printString("A") //A가 실행된다.
    .then(() => {
      return printString("B") // A가 실행된 후 B를 실행한다.
    })
    .then(() => {
      return printString("C") //A, B가 실행된 후 C를 실행한다.
    })
  }
  printAll()

[Promise의 파라미터]
-- resolve: 비동기 작업의 처리 과정에서 '성공' 했다는 것을 의미한다.
처리를 성공하였을 때 .then()을 이용하여 넘기는 인자를 사용할 수 있다.

-- reject: 비동기 작업의 처리 과정에서 '실패' 했다는 것을 의미한다.
처리를 실패하였을 때 .catch()를 이용하여 넘기는 인자를 사용할 수 있다.

[Promise의 세 가지 상태]
-- 대기(pending): 이행하거나 거부되지 않은 초기 상태를 의미한다.
-- 이행(fulfilled): 연산이 성공적으로 완료되었음을 의미한다.
-- 거부(rejected): 연산이 실패했음을 의미한다.

new 키워드를 이용해 Promise 객체를 만드는 순간 대기(pending) 상태가 된다. Promise 실행함수가 가지고 있는 두 개의 파라미터 중 resolve를 실행하면 이행(fulfilled) 상태가 된다. reject를 실행하면 거부(rejected) 상태가 된다.

promise를 사용하니 코드의 들여쓰기도 덜해지고, 일의 순서도 더 명확히 눈에 보이는 것을 볼 수 있다. 그러나 이것도 task가 많아지면 많아질수록 promise chaining이 발생할 수 있다.

promise chaining을 예방하고 코드를 더 깔끔하게 사용하기 위해 async await 라는 개념이 나왔다.

3. async await

const printString = (string) => {
    return new Promise((resolve, reject) => {
      setTimeout( //일정 시간 뒤에 실행한다.
        () => {
         console.log(string)
         resolve()
        }, 
        Math.floor(Math.random() * 100) + 1
      )
    })
  }
  const printAll = async () => {
  const a = await printString('A')
  const b = await pringString('B')
  const c = await printString('C')
  printAll();
  }

await는 일반 함수에서 사용하면 에러가 발생한다. 반드시 async가 선언된 함수 내부에서 사용해야 한다. 이 점만 주의해서 사용하면 된다!

await 개념은 자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법이다.
기존의 비동기 처리 방식인 callback, promise의 단점을 보완하여 가독성이 좋은 코드를 작성할 수 있게 된다. 마치 일반 함수를 실행하는 것처럼 정갈하고 chaining도 더이상 일어나지 않는다는 장점이 있다

오늘은 동기와 비동기에 대하여 공부하였다.
내일은 웹에서 정보를 가져오는 방법인 fetch에 대하여 공부한다.
오늘은 여기까지 :)

좋은 웹페이지 즐겨찾기