async 함수 안에서 await을 마주치면 뒤에 있는 promise가 fulfilled가 될 때까지 함수 바깥에 있는 코드를 실행하다가 다시 함수 안으로 돌아와서 코드를 이어서 실행한다.
async에 대한 중요한 사실은 하나가 더 있다. async 함수는 항상 Promise를 리턴한다는 점이다.
//asyncFunctions.js에서 직원데이터를 출력하지 않고 리턴하도록 해보자.
export async function getEmployees() {
const response = await fetch('https://learn.codeit.kr/api/employees');
const data = await response.json();
return data;
};
//main.js에서 getEmployees 함수를 사용해보자.
import { getEmployees } from './asyncFunctions.js';
const employees = getEmployees(); //async는 항상 promise를 리턴하기 때문
console.log(employees);
getEmployees 함수의 리턴 값을 employees 변수에 할당하고 employees 변수를 출력한다. 코드를 실행해보면?
분명히 getEmployees 함수 안에서는 await을 잘 활용해서 직원 데이터를 추출해 냈음에도 불구하고 이 데이터를 employees 변수에 할당해서 출력하니까 promise pending이라고 나온다. 그 이유는 async 함수는 항상 promise를 리턴하기 때문이다.
async 함수가 promise를 리턴해야 하는 이유는 무엇일까?
함수가 async라는 것은 보통 안에 await문이 있다는 것이고, await 문이 있다는것은 어떤 비동기 작업, 비교적 오래 걸리는 작업을 처리한다는 것이다. 그러니 async 함수 자체도 끝까지 실행하려면 꽤나 오랜 시간이 걸린다.
getEmployees 함수도 끝까지 실행하려면 fetch와 json 함수를 기다려야한다. 그렇기 때문에 getEmployees 함수를 호출하면 리턴값을 바로 알 수가 없다. 그래서 async 함수는 일단 promise를 리턴해 주고 함수의 body가 다 실행되고 리턴값이 정해지면 promise를 fulfilled 상태로 바꿔주고 함수의 리턴 값을 promise의 결과값으로 채워준다.
//main.js에서 getEmployees 함수를 사용해보자.
import { getEmployees } from './asyncFunctions.js';
const employees = await getEmployees(); //await 추가
console.log(employees);
그니까 promise의 결과값을 받아오려면 앞에 꼭 await을 써줘야 한다! 조금 복잡하게 느껴지지만 promise에서 성공 결과값을 받아오려면 await을 써야 한다는 점을 잘 기억하도록 하자.
- 함수 안에서 Promise를 리턴하면 그 Promise를 그대로 리턴
- 함수 안에서 평범한 값을 리턴하면 그 값을 결괏값으로 갖는 Promise를 리턴
따라서 async 함수에서 리턴하는 값을 가져오려면 await을 활용!
한번 더 정리!
1. const employees = await getEmployees();로 getEmployees함수를 실행하면 pending 상태의 promise가 바로 리턴된다.
2. getEmployees 함수(asyncFunctions.js)를 끝까지 실행하는데 시간이 조금 걸리는데, 끝까지 실행이 되고 data를 리턴하면
3. data가 ( const employees = await getEmployees(); //promise ) promise에 채워지고 promise의 상태는 fulfilled로 바뀐다.
4. getEmployees() 앞에 await을 써줬기 때문에 promise의 결과값이 employees 에 할당된다.
코드를 실행해보면 직원 데이터가 잘 출력된것을 확인 할 수 있다.
여담
이제 직원 데이터를 마음대로 활용할 수 있다.
//main.js
import { getEmployees } from './asyncFunctions.js';
const employees = await getEmployees(); //promise
const employee = employees[0]
console.log(employee);
이렇게 배열에서 요소 하나만 가져올 수도 있다. 하지만 여기서 주의할 점이 하나 있다. async 함수 본문에서 promise를 리턴하는 경우인데,
//asyncFunctions.js
export async function getEmployees() {
const response = await fetch('https://learn.codeit.kr/api/employees');
return response.json();
};
예를 들어 코드를 위처럼 바꾸면 response.json은 promise이다. 이런 경우엔 getEmployees가 리턴하는 promise(main.js의 4번째 줄)는 함수가 리턴하는 promise(asyncFunctions.js의 4번째 줄)와 동일한 상태와 결과값을 갖게 된다.
그러니까 response.json이 성공해서 해당하는 promise가 fulfilled 상태가 되고, 파싱된 데이터를 결과값으로 갖게 되면 getEmployees가 리턴하는 promise도 filfilled 상태가 되고 파싱된 데이터를 결과값으로 갖게 된다. getEmployees 앞에는 이미 await이 있기 때문에 코드를 실행해봐도 결과가 잘 출력된다.
하지만 이 코드는 response.json이 비동기 작업이라는걸 알기 힘들기 때문에 이전에 작성했던 코드를 더 권장한다.
//asyncFunctions.js
export async function getEmployees() {
const response = await fetch('https://learn.codeit.kr/api/employees');
const data = await response.json();
return data;
};
이렇게 써있으면 어떤 작업을 await하는지 한눈에 알아보기가 쉽고 함수의 흐름에 대해 생각하기도 더 편하다.
'코린이 개념잡기 > 비동기 자바스크립트' 카테고리의 다른 글
promise rejected 상태 이해하기 (0) | 2024.12.25 |
---|---|
오류 처리하기 (try catch) (1) | 2024.12.23 |
async 함수 사용시 주의사항 (0) | 2024.12.23 |
async 함수 (0) | 2024.12.23 |
await 문법 (0) | 2024.12.22 |