[JavaScript] Top-level await (+약간의 Promise)
Top-level await
js ES2022(ES13)부터 도입된 기능으로, 모듈 스코프에서 직접 await 키워드를 사용할 수 있게 해준다.
이전에는 async 키워드가 있는 스코프 내에서만 await를 통해 해당 스코프에서 비동기 동작이 완료되기까지 블로킹할 수 있었는데
모듈단위에서 await를 통해 특정 비동기 함수의 동작이 완료되기까지 하위 모듈의 동작을 막을 수 있다.
1. 기존의 await 사용 제한과 Top-level await의 등장
기존 await 키워드는 반드시 async 함수 내부에서만 사용할 수 있었다.
따라서, await를 모듈의 최상위 레벨에서 사용하려면 async 함수를 감싸야 했다.
// 기존 방식 (async 함수로 감싸야 함)
async function main() {
const result = await fetchData();
console.log(result);
}
main();
Top-level await을 사용하면 모듈의 최상위 레벨에서 await를 직접 사용할 수 있다.
=> async 함수를 감싸는 불필요한 작업 없이 비동기 작업을 간단히 처리
// Top-level await 사용 예시
const result = await fetchData();
console.log(result);
2. Top-level await의 특징
- 모듈 스코프에서만 사용 가능
Top-level await은 ES 모듈(ECMAScript Module)에서만 사용할 수 있.
스크립트 파일(script 태그, 브라우저의 전역 스코프)에서는 사용 불가 - 비동기 작업을 기다림
Top-level await을 사용하는 모듈은 해당 비동기 작업이 완료될 때까지 다른 모듈의 실행을 블록 - 의존 모듈 순서 보장
Top-level await이 있는 모듈은, 해당 모듈이 의존하는 모듈의 비동기 작업이 모두 끝난 후에 실행된다. (모듈 간 실행 순서 보장)
Promise와 await의 기본 관계
- await 키워드는 Promise가 완료될 때까지(성공 또는 실패) 기다리는 역할을 한다.
- await는 항상 Promise 객체를 처리
- 성공(resolve)시 결과값 반환, 실패(reject)하면 에러 던지기
const fetchData = () => Promise.resolve("data");
async function main() {
const result = await fetchData(); // Promise가 완료될 때까지 기다림
console.log(result); // "data"
}
main();
Top-level await에서 Promise와의 관계
Top-level await는 Promise를 더 쉽게 처리하기 위한 상위 수준 구문
Promise는 여전히 비동기 작업의 기본이며, Top-level await은 이를 더 직관적이고 간단하게 사용하는 도구이다.
Top-level await도 내부적으로 Promise를 기다리는 메커니즘을 사용한다. (모듈의 최상위 스코프에서 Promise를 처리할 때 유용)
기존의 Promise를 처리하려면 then 체인을 사용하거나, async 함수를 작성했다.
Top-level await을 사용하면 코드가 더 간결해지고, 명령형으로 작성 가능하다.
1. 간단 예제
Promise와 then 체인을 사용한 기존 방식
import fetch from "node-fetch";
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
Top-level await 방식
import fetch from "node-fetch";
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
2. todoList.mjs
// todoList.mjs
let todoList;
(async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
todoList = await response.json();
})();
export { todoList };
// index.mjs
import { todoList } from "./todoList.mjs";
console.log(todoList); // undefined
- todoList.mjs: todoList를 조회한 후 결과를 내보내는 모듈
- index.mjs: todoList.mjs의 결과를 import하여 출력하는 모듈
index.mjs에서 todoList.mjs의 비동기 처리가 완료되지 않은 시점에 todoList로 접근이 가능하기 때문에 undefined를 출력
=> todoList.mjs에서 Promise객체를 반환으로 해결
Promise와 then 체인을 사용한 기존 방식
Promise 객체의 then 메서드를 활용해 비동기 처리 직후 todoList에 접근한다.
문제:
- promise를 사용하지 않아도 todoList로 접근 가능 (위험요소를 포함)
- 복잡한 코드
// todoList.mjs
let todoList;
export default (async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
todoList = await response.json();
})();
export { todoList };
// index.mjs
import promise, { todoList } from "./todoList.mjs";
promise.then(() => {
console.log(todoList); // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
});
Top-level await 방식
index.mjs는 todoList.mjs의 await가 모두 실행되기 전(비동기 처리가 완료되기 전까지) 동작을 중지한다.
(Top-level await를 사용한 모듈이 하나의 거대한 async 함수처럼 동작)
따라서 index.mjs에서는 todoList로 바로 접근을 해도, 비동기 처리가 완료됐다는 것을 보장하기 때문에 원하던 결과를 얻을 수 있게 된다.
// todoList.mjs
let todoList;
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
todoList = await response.json();
export { todoList };
// index.mjs
import { todoList } from "./todoList.mjs";
console.log(todoList); // {userId: 1, id: 1, title: 'delectus aut autem', completed: false}
ref.
https://fe-developers.kakaoent.com/2022/220728-es2022/
자바스크립트의 새로운 기능들 | 카카오엔터테인먼트 FE 기술블로그
이동희(east) 스토리FE개발팀 프론트엔드 개발자입니다. 음주가무를 즐기며 활동적인 모든 것을 사랑합니다.
fe-developers.kakaoent.com
https://velog.io/@pds0309/top-level-await
top level await
Top-level await enables modules to act as big async functionsES2022에서 나온 기능으로 모듈의 최상위 스코프에서 비동기 동작을 await하여 사용할 수 있다.이전에는 async 키워드가 있는 스코프 내에서만 await
velog.io