Javascript async/await

shelly·2022년 4월 29일

async / await에 대하여

Promise를 활용하여 동기 함수처럼 동작한다.

function func() {
  setTimeout(() => {console.log(1)}, 6000)
  setTimeout(() => {console.log(2)}, 3000)
  setTimeout(() => {console.log(3)}, 1000)  
}

func() // 3 2 1 
async function asyncFunc() {
  await new Promise((resolve) => setTimeout(() => {console.log(1); resolve()}, 6000))
  await new Promise((resolve) => setTimeout(() => {console.log(2); resolve()}, 3000))
  await new Promise((resolve) => setTimeout(() => {console.log(3); resolve()}, 1000))
}

asyncFunc() // 1 2 3
  • 비동기 함수 func()
    출력은 3, 2, 1 순서이며, 함수 실행 시간은 약 6초이다.
    setTimeout은 비동기함수이며, setTimeout 함수를 포함한 func 함수 또한 비동기 함수이다. s
    즉, 각각의 setTimeout에 설정한 시간이 모두 흘러갈 때 까지 기다리는 것이 아니라, 연속적으로 세 개의 setTimeout함수 스케쥴링을 진행한다.
    때문에 timeout시간이 가장 빠른 3이 먼저 출력되고 그 이후에 2와 1이 출력된다.
    그리고 총 함수 실행시간은 가장 긴 timeout시간을 가진 (약) 6초이다.

  • async 함수 asyncFunc()
    출력은 1, 2, 3 순서이며, 함수 실행 시간은 약 10초이다.
    Promise 앞에 사용된 await은 Promise가 settled 상태가 될 때 까지 기다린다. Promise가 settled 상태가 되면 resolve한 결과값을 반환한다.
    즉 첫 setTimeout함수에서 6초를 기다린 후 console.log(1)을 실행하고 resovle를 실행한 후에, 두 번째 setTimeout 함수를 스케쥴링한다.
    마치 동기 함수처럼 동작하며, 1, 2, 3 순서를 보장하며 실행된다. 하지만 모든 동작을 기다리는 만큼 함수 실생 시간은 10초가 걸린다.

await은 async함수 내부에서만 사용할 수 있다.

// 함수 선언문
async function asyncFunc1() {
  const response = await apiRequest();
  console.log(response)
}

// 함수 표현식
const func = async function () {
  const response = await apiRequest();
  console.log(response)
}

// 화살표 함수
const asyncFunc2 = async () => {
  const response = await apiRequest();
  console.log(response)
}

await은 Promise를 반환하는 함수에만 사용할 수 있다.

await 키워드는 Promise가 settled 상태로 바뀌면서 resolve한 값을 반환한다.
Promise가 아닌 다른 코드 앞에 작성할 경우, 아무런 동작을 하지 않는다.

  • 잘못된 예시
// 잘못된 예시
const func = async () => {
  await setTimeout(() => {console.log('Hello')}, 1000)
  console.log('world!')
}

func() // world! Hello

setTimeout은 비동기 함수이지만, Promise를 사용하지 않는다.
따라서 await 키워드가 정상동작하지 않는다.

  • 적절한 예시
// 적절한 예시
const func = async () => {
  const message = await new Promise(resolve => setTimeout(() => {console.log('Hello'), resolve('world!')}, 1000))
  console.log(message)
}

func() // Hellot world!

setTimeout함수가 스케쥴링 하고, await키워드는 Promise가 settled상태로 바뀔 때 까지 대기한다.
1초 뒤 'Hello'가 콘솔에 출력되고 resolve 함수를 실행하며 Promise는 settled 상태로 변한다.
이를 감지한 await은 resolve 반환값인 'world!' 문자열을 message에 반환한다.
그 다음에 console.log(message)를 실행하여 'world!'가 콘솔에 출력되게 된다.

async 함수는 암묵적으로 반환값을 resolve하는 Promise를 반환한다.

async function getId() {
  const response = await apiRequest(); // {id : 100}
  return response.id
}

const findId = async () => {
  const id = await getId()
  console.log(id) // 100
}

위에서 말했듯이, await는 Promise를 반환하는 함수 앞에 사용될 수 있다.

getId는 Promsie를 반환하지 않고, response.id라는 값을 반환한다. 그런데 findId의 await는 getId가 값을 반환할 때 까지 기다리고, id 값을 정상적으로 출력한다.

그 이유는 async함수는 암묵적으로 반환값을 resolve하는 Promise를 반환하기 때문이다.
아래의 두 코드는 동일한 의미이다.

async function getId1() {
  const response = await apiRequest(); // {id : 100}
  return response.id
}

async function getId2() {
  const response = await apiRequest(); // {id : 100}
  return Promise.resolve(response.id)
}

0개의 댓글