Binding, Module 관리, Promise

jingjinge·2025년 1월 4일

ASAC_07

목록 보기
7/13

Binding

지난 번 글에서 호이스팅을 정리했다.

화살표 함수는 왜 쓰는 것일까?

공부하다가 겪은 실제 사례를 가져오겠다!


암묵적 바인딩

validateAndSliceName(input) {
        let result;
        const validators = [
            this.nameInputValidate,
            this.commaValidate,
            this.nameValidate,
        ];
        for (const validator of validators) {
            result = validator(input);
            if (!result.success) return result;
        }
        return result; // 모든 검사를 통과한 최종 결과
    }

Class 내부의 유효성 체크를 위한 Method이며, 싸이클을 돌리기 위해 method들을 변수에 초기화했다.
하나의 예시만 가져오겠다.

//arrow function을 사용
nameInputValidate = (input) => {
        return typeof input === "string" && input.length !== 0
            ? { success: true, errorCode: 100 }
            : { success: false, errorCode: 101 };
    };
//암묵적 바인딩으로 따로 명시적 바인딩을 사용하지 않고, class 내 lexical scope로 바인딩 됨을 이용
const validators = [
            this.nameInputValidate,
        ];

화살표 함수Lexical Scope로 호출부가 아닌 선언부에서 Scope Chain을 진행한다.

따라서 현재 선언된 class context에 바인딩되며, 이는 즉 정적 바인딩을 뜻한다.

만약 일반 함수로 작성되었다면, 호출부의 this를 찾아 해당 Scope에 Binding된다.

그것은 즉 동적 바인딩을 뜻한다.

일반 함수로 해당 class에 바인딩 하는 방법은 없을까?


명시적 바인딩

nameInputValidate = (input) => {
        return typeof input === "string" && input.length !== 0
            ? { success: true, errorCode: 100 }
            : { success: false, errorCode: 101 };
    };
const validators = [
            this.nameInputValidate.bind(this),
        ];

현재 속한 class에 명시적으로 바인딩을 하는 방법이다.

필자는 기존에는 이 방법을 사용했다가 간결해보이는 arrow function을 채택했다.


Module 관리

태그

JS의 사이즈가 커질수록 아래와 같은 문제가 발생하기 시작하였다.

  1. 성능 문제 : 페이지 로딩 시 동시에 모든 스크립트를 한번에 로드 후 실행, 큰 규모 프로젝트에 로딩 속도 문제
    • 성능 최적화의 한계 : 모든 스크립트를 동기적으로 로드 시 브라우저는 페이지 렌더링을 일시 중지
  2. 의존성 관리의 어려움 : 여러 개의 스크립트 간 의존성 관리(스크립트 간의 로드 순서 관리) 취약
  3. 전역 스코프 문제 : 모든 <script> 스크립트들은 기본적으로 전역 스코프로 변수 이름 충돌이나 오염 발생
  4. 코드 재사용의 어려움 : 모든 페이지에서 동일한 스크립트를 사용 시 코드의 재사용이 어려움

이에 따라 모듈 시스템에 대한 요구 등장 ← 과거에는 IIFE, 클로저, 스코프 개념들을 조합하여 모듈을 힘들게 흉내


ESM

ESM이란 ECMAScript Modules의 줄임말로, import와 export를 지원한다.

NamedExport

위 사진의 namedExport.js에 해당한다. 외부에서 호출해야할 함수나 객체, 메소드, 클래스 등을 각 선언부 앞에 export를 붙여준다.

호출하는 main.js에서는 {}안에 불러온다.

defaultExport

위 사진의 defaultExport.js에 해당한다. 외부에서 호출해야할 함수나 객체, 메소드, 클래스 등 단 한개만 파일 내부에 작성하고, 가장 하단에 export default ${호출명}을 써준다.

호출하는 main.js에서는 그냥 불러온다.

나는 class는 defaultExport를 사용하고, 함수만 주르르 작성했을 때는 NamedExport를 사용한다.


CJS

CJS란 Common JavaScript의 줄임말이다.

require는 런타임에 모듈을 로드하고, import는 정적으로 모듈을 로드하며 최적화를 지원한다.

  • CJS 를 지원하는것이 중요한 이유 = Node.js 활용한 SSR 사용 서비스를 위해 CJS 지원 필요
  • ESM 을 지원하는것이 중요한 이유 = Tree-shaking 을 지원하는 ESM 이 브라우저 성능에 중요
    • CJS - 모듈 동기 로드 : 빌드타임에 정적 분석 불가 → 런타임에 모듈 관계 파악
    • ESM - 모듈 비동기 로드 : 정적 모듈 의존 강제 = 빌드타임에 Tree-shaking 가능

Promise

React를 처음 다뤄보았을 때, 문법적으로 가장 낯설었다. 정말 새로운 문법 형식이라고 생각하고 다가가는게 좋다고 생각한다.

생긴 이유: callback 지옥 해결

  • Promise = CallBack + Asynchronous 로 이해한다.

new Promise((resolve, reject) => {
	const result = producing()
	if (result.success) resolve(result.body)
	if (result.failed) reject(result.error)
})
	.then((body) => { consuming(body) })
	.catch((error) => { consuming(error) })

Promise에는 크게 3단계로 나뉜다.

  1. ispending(결과가 나오기 전)
  2. resolve(성공) - .then - fullfilled
  3. reject(실패) - .catch - rejected

처음 말했듯이 아예 처음 보는 문법이라고 생각하자.

  1. 성공 조건에는 resolve 콜백을 실행하고(이름은 본인 맘대로)

  2. 실패 조건에는 reject 콜백을 실행한다(마찬가지)

    주의 Promise는 return이 아닌 resolve로 반환한다는 점 명심

아 조금 불편한데.. 항상 저렇게 써야할까..


async, await

asyncawait
Promise를 사용할 때, .then과 .catch 체인을 계속 사용하는 것이 불편하다면, JavaScript의 async와 await 문법을 활용하면 훨씬 더 직관적으로 코드를 작성할 수 있다.

async와 await은 Promise의 동작을 동기적인 코드처럼 작성할 수 있게 해주는 문법이다.


  let promise = new Promise(
		function caller(resolve, reject) {
			const produced = producing()
			if (succeeded) resolve(produced)
			if (failed) reject(produced)
		}
	)
//		.then(function resolve(produced) { consuming(produced) })
//		.catch(function reject(produced) { consuming(produced) })
let fulfilled = promise    // Promise {<fulfilled>, '완료!'}
let result = await promise // '완료!' //toplevel await문제가 발생할 수 있다.

await문은 Promise 객체를 언패킹 해준다고 생각하면 좋다.

  • await는 항상 async안에 존재해야한다.
    • 하지만 ES2022부터 TopLevelAwait를 지원하는데, 버전이 낮은 브라우저에서 동작을 안할 가능성이 있다.

출처: ASAC 07기 강의자료

0개의 댓글