모던 자바스크립트 개발 [1] – 모듈, Exporting / Importing, Top-Level await

모듈

  • 모듈이란 디테일한 실행 로직을 캡슐화한 재사용 가능한 코드를 의미한다.
  • 모듈은 import와 export라는 요소를 가지고 있는데, import의 경우 코드에서 사용하기 위한 모듈을 불러오는 기능이고 export는 다른 코드에서 사용할 수 있도록 public API로 만드는 기능이다.
  • 파일 하나 당 모듈 하나를 작성한다.
  • import나 export는 호이스팅 때문에 함수나 코드 블록 안에서 사용하지 못한다. top-level에서만 사용할 수 있다.
  • 앞선 슬라이드에서 모듈 파일을 다운로드 하는 것은 비동기로 진행된다고 되어 있지만, 모듈을 임포팅하는 것 자체는 동기로 진행된다. 이유는 동기로 진행을 해야 번들링과 사용하지 않는 코드를 삭제할 수 있기 때문이다. 수없이 많은 코드 중 사용해야 하는 함수나 값만 가져오려면 순차적으로 임포팅이 처리되어야 한다.
  • 자바스크립트 모듈에서는 모듈 코드를 카피해서 사용하는 것이 아니라 live connection을 유지하고 있으므로, 모듈의 코드가 바뀌면 실행하는 코드에서도 바뀐 코드가 그대로 적용된다.

Exporting / Importing

console.log('Exporting module');

const shippingCost = 10;
export const cart = [];

export const addToCart = function (product, quantity) {
  cart.push({ product, quantity });
  console.log(`${quantity} ${product} added to cart`);
};

const totalPrice = 237;
const totalQuantity = 23;

export { totalPrice, totalQuantity as tq };

export default function (product, quantity) {
  cart.push({ product, quantity });
  console.log(`${quantity} ${product} added to cart`);
}
  • 모듈 밖에서 사용할 수 있게 하려면 export 키워드를 앞에 붙여야 한다. 여러 개를 묶어서 export 하려면 {} 안에 작성해주고, 이름을 붙이려면 as를 사용한다. export 키워드만 사용한 요소는 named export라고 부른다. import 할 때 해당 이름을 그대로 사용하기 때문이다.
  • default export는 보통 한 모듈에서 한개의 요소만 export 할 때 사용한다. import 할 때 이름을 원하는대로 import 한다.
console.log('Importing module');

// import { addToCart, totalPrice as price, tq } from './shoppingCart.js';
// addToCart('bread', 5);
// console.log(price, tq);

// import * as ShoppingCart from './shoppingCart.js';
// ShoppingCart.addToCart('bread', 5);

import add, { cart } from './shoppingCart.js';
add('pizza', 2);
add('bread', 5);
add('apples', 4);

console.log(cart);
  • 작성한 모듈을 그냥 사용하려고 하면 Uncaught SyntaxError: Cannot use import statement outside a module가 발생한다. html 파일에서 type=”module”을 명시해줘야 한다. (e.g. <script type="module" defer src="script.js"></script>)
  • 메인 js 파일보다 모듈 js 파일이 먼저 실행되므로 Exporting module이 먼저 출력된다.
  • named export는 {}를 사용한다. default export 요소는 {} 안에 넣지 않고, 원하는 이름으로 import 하면 된다.

Top-level await(ES2022)

console.log('Start fetching');
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await res.json();
console.log(data);
console.log('Something');
  • ES2022부터는 await을 async 밖, 즉 Top-level에서 사용할 수 있게 되었다. 하지만 Top-level에 있으므로 메인 코드의 실행을 블로킹하게 된다. 따라서 필요에 따라 잘 사용해야한다.
  • 또한 모듈에서 Top-level await을 사용할 경우 모듈을 import 하는 코드에서도 블로킹이 발생하기 때문에 더욱 유의해야 한다.
const getLastPost = async function () {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const data = await res.json();

  return { title: data.at(-1).title, text: data.at(-1).body };
};

const lastPost = getLastPost();
console.log(lastPost); // Promise 객체

// Not very clean
// lastPost.then(last => console.log(last));

const lastPost2 = await getLastPost();
console.log(lastPost2);
  • async 함수를 일반적으로 호출해서 데이터를 저장할 경우 Promise 객체가 리턴되지만, await을 사용하면 바로 해당 데이터를 리턴받을 수 있어서 코드가 간결해지고 이해하기 쉬워진다.

Leave a Reply

Your email address will not be published. Required fields are marked *