2025/03/26

 

단일 파일 컴포넌트에서의 스타일

✅전역 CSS

  • 페이지 전체에 적용 => 충돌 발생 가능

 

다른 컴포넌트의 스타일과 충돌 피하는 방법

  • 특정 컴포넌트만의 스타일 지정
  • 범위 CSS(Scoped CSS) : 컴포넌트가 렌더링하는 요소에 특성 기반의 추가적인 식별자 부여
  •  CSS 모듈

 

범위 CSS

 

 

 

 

 

 

 

 

 

CSS 모듈

 

슬롯(slot)

❗슬롯은 "부모 → 자식" 방향으로 동작합니다!

✅ 부모 컴포넌트가 자식 컴포넌트의 slot 자리에 콘텐츠를 끼워 넣는 구조예요.

즉, 슬롯은 자식이 "빈 자리"를 열어두고,
부모가 그 빈 자리에 "콘텐츠"를 전달하는 거예요.

 

기본 슬롯

 

명명된 슬롯(식별자 사용) <- 중요

화면 레이아웃 관리 목적으로 자주 사용

 

 

범위 슬롯

자식 컴포넌트의 데이터를 이용해 바인딩하는 경우 범위 슬롯 사용

  • 전달된 데이터는 슬롯 템플릿 내부 범위에서만 사용 가능

✔️ 일반 슬롯: 부모가 콘텐츠를 자식에게 넣어줌
✔️ 범위 슬롯: 자식이 데이터를 제공하고, 부모가 그걸 사용해서 화면을 구성

 

 

 

 

 

동적 컴포넌트(Dynamic Component) - 개념만 알아두기

화면의 동일한 위치에 여러 컴포넌트를 표현해야 하는 경우 사용

 

 

사용자 정의 v-model 만들기 <- 중요

컴포넌트에서 v-model을 직접 지원하도록 커스터마이징할 수 있다는 뜻!

 

2025/03/25

✔️ 지금까지 Vue를 공부했던 방식

  • HTML 파일 하나 안에서  Vue를 CDN으로 불러와서 사용
<script src="https://unpkg.com/vue@3"></script>
  • Vue 인스턴스를 직접 만들어서 <div id="app">에 마운트

✔️ 지금부터 사용하는 방식: 실제 프로젝트 방식

 

프로젝트 생성

1.

npm init vue

 

2. 프로젝트 이름 설정

 

3. 프로젝트 폴더로 진입

cd test-vue-app

npm install

 

생성 완료

 

=> 프로젝트 실행

npm run dev

💡Vite(비트)란?

빠르고 가벼운 프론트엔드 개발 환경을 제공하는 모던 빌드 도구

 

특징

✅ 빠른 실행

✅ 실시간 반영(HMR)

✅ 간편한 설정

✅ ES 모듈 기반

 


💡 단일 파일 컴포넌트란?

.vue 확장자를 가진 파일 하나에 화면(template), 로직(script), 스타일(style)한 곳에 모아서 작성하는 Vue만의 컴포넌트 방식. 즉, 하나의 파일이 하나의 독립된 화면 조각 역할 함.

 

  • 재사용성
  • 복잡성

을 고려하여 컴포넌트 분리

 

📌컴포넌트 전역 등록

  • 한 번 등록하면 애플리케이션 전역에서 어디서든 사용할 수 있는 방식

main.js

import { createApp } from 'vue'
import App from './App.vue'
import MyButton from './components/MyButton.vue'

const app = createApp(App)
app.component('MyButton', MyButton)

app.mount('#app')

 

✅ 특징

  • 모든 컴포넌트에서 import 없이 사용 가능
  • 코드가 간결하지만 모든 페이지에 포함되므로 번들 크기가 커질 수 있음
  • 이름 충돌 위험 있음

 

 

📌컴포넌트 지역 등록

  • 해당 컴포넌트 파일 안에서만 사용할 수 있도록 등록하는 방식

App.vue

<script>
import CheckboxItem from './components/CheckboxItem.vue';

export default {
  name : 'App',
  components : {CheckboxItem}
};
</script>

 

✅ 특징

  • 사용하는 컴포넌트만 메모리에 올라감 → 최적화에 유리
  • 재사용 가능한 컴포넌트라면 여러 파일에 중복 등록 필요
  • 유지보수 시 명시적이라 가독성 좋음

 


💡컴포넌트의 조합

컴포넌트 트리 구조

 

 

✅ 1. 부모 → 자식: props로 데이터 전달

📌 전달 흐름

  1. 부모가 데이터를 정의하고
  2. 자식에게 <컴포넌트 :속성="값" /> 형태로 전달
  3. 자식 컴포넌트는 props 옵션으로 해당 데이터를 받음

❗ ❗ 속성으로 전달받은 데이터는 변경 불가(읽기 전용)

❗ ❗ 부모에서 속성 값을 변경 시 => 자식은 자동으로 다시 렌더링됨

 

<App.vue  부모 컴포넌트>

<template>
  <div>
    <h2>관심있는 K-POP 가수?</h2>
    <ul>
      <CheckboxItem
        v-for="idol in idols"
        :key="idol.id"
        :name="idol.name"        //중요
        :checked="idol.checked"  //중요
      /> 
    </ul>
  </div>
</template>

<script>
import CheckboxItem from './components/CheckboxItem.vue'

export default {
  name: 'App',
  components: { CheckboxItem },
  data() {
    return {
      idols: [
        { id: 1, name: 'BTS', checked: true },
        { id: 2, name: 'Black Pink', checked: false },
        { id: 3, name: 'EXO', checked: false },
        { id: 4, name: 'ITZY', checked: false }
      ]
    }
  }
}
</script>

 

 

<CheckboxItem.vue 자식 컴포넌트>

<template>
  <li>
    <input type="checkbox" :checked="checked" /> {{ name }}
  </li>
</template>

<script>
export default {
  name: 'CheckboxItem',
  props: {
    name: String,
    checked: {
      type: Boolean,
      default: false
    }
  }
}
</script>

 

 

✅ 2. 자식 → 부모: emit으로 이벤트 전달

📌 전달 흐름

  1. 자식 컴포넌트에서 $emit('이벤트명', 데이터) 호출
  2. 부모 컴포넌트는 해당 이벤트를 @이벤트명="함수" 방식으로 감지
  3. 부모 컴포넌트가 전달된 데이터를 받아 처리

 

<InputName.vue 자식 컴포넌트>

<template>
  <div style="border: solid 1px gray; padding: 5px">
    이름: <input type="text" v-model="name" />
    <button @click="$emit('nameChanged', { name })">이벤트 발신</button>
  </div>
</template>

<script>
export default {
  name: 'InputName',
  data() {
    return { name: '' }
  }
}
</script>

 

 

 

<App4.vue 부모 컴포넌트>

<template>
  <div>
    <InputName @nameChanged="nameChangedHandler" />
    <h3>App 데이터: {{ parentName }}</h3>
  </div>
</template>

<script>
import InputName from './components/InputName.vue'

export default {
  name: 'App4',
  components: { InputName },
  data() {
    return { parentName: '' }
  },
  methods: {
    nameChangedHandler(e) {
      this.parentName = e.name
    }
  }
}
</script>

 

이벤트 처리 과정

 

 

부모-자식-손자 컴포넌트 계층 구조에서 이벤트 전송

 

 


 

 

✅ 3. 이벤트 유효성 검증(emits 옵션)

 

📌 개념

Vue 3에서는 $emit()으로 발신하는 이벤트가 정상적인 이벤트인지 검증 가능

 

✅ 기본 검증 방식

export default {
  emits: ['nameChanged']  // 허용된 이벤트 목록
}

→ 위 이벤트 외의 emit이 발생하면 콘솔에 경고가 뜸


✅ 고급 검증: 데이터 유효성 체크

 
export default {
  emits: {
    nameChanged: (payload) => {
      return typeof payload.name === 'string' && payload.name.length >= 2
    }
  }
}

→ payload.name이 문자열이 아니거나 2자 미만이면 경고 발생

 

 


✅ 4. 이벤트 에미터 (mitt 라이브러리)

📌 개념

Vue 컴포넌트 간 이벤트를 전역(Global)으로 주고받기 위한 이벤트 버스 도구
→ 형제 컴포넌트끼리 통신할 때 유용

 

✅ 설치

npm install mitt
 
 

 


 

2025/03/24 

 

HTML의 스타일 적용

  • 클래스명, 속성명 지정시 케밥 표기법 지정
  • Javascript : '-' 표기가 연산자이므로 사용 불가 => 키멜표기법 사용
  • 스타일 적용 순서
    • 요소의 기본 스타일 -> .text 스타일 -> .over 스타일 -> 인라인 스타일

 

 

 

인라인 스타일

v-bind:style="value" 로 작성

=> 데이터 속성에 자바스크립트 객체로 작성

=> value : 스타일 속성명, 스타일 값

 

 

1. 객체로 표기

style1 객체 사용

 

 

2. 문자열로 표기 ( 2개 이상이면 { }로 묶기)

템플릿 파트에서 객체로 표기

 

두 가지 방법은 취향의 차이,

하지만 후자로 하면 style1이라는 표기가 빠지니 코드가 조금 더 단순해지는 효과가 있음.

 

 

 

3. 배열로 표기

 

 

 


 

 

 

 

CSS 클래스 바인딩

v-bind:class="value" 또는 축약표현 :class="value" 로 작성

=> 클래스명 문자열을 바인딩

=> vlaue : 클래스명

 

1. 문자열로 표기

 

 

 

 

2. 배열로 표기

 

 

 

 

3. 객체로 표기

 

 

=> true/false 값을 가진 객체를 바인딩하는 방법

  • 3항 연산자로 클래스 지정 제어시 여러 개인 경우 복잡도 상승
  • 객체로 바인딩해서 속성명으로 클래스 명 지정
    • 속성 값으로 해당 클래스 적용 여부를 true/false 지정



 

 

 


 

 

 

동적 스타일 바인딩

v-bind:style 또는 축약형 :style 사용

=> Vue에서 HTML 요소의 스타일을 자바스크립트 데이터에 따라 동적으로 변경할 수 있도록 하는 기능

2025/03/19 

 

 

📌 Vue 디렉티브(Directive)란?

디렉티브(Directive)는 Vue에서 HTML 태그에 추가적인 반응형 동작을 부여하는 특수 속성

  • 디렉티브 값은 문자열이 아님, JS 표현식(자바스크립트 문법이 적용됨)

 

v-text 디렉티브

  • innerTEXT 속성과 연결, 태그 문자열이 그대로 나타남
  • 단방향 데이터 바인딩
<div id="app">
    <h2 v-text="message"></h2>
</div>
<script>
    let model = { message: '<h1>Hello Vue3!</h2>' };


 

v-html 디렉티브

  • innerHTML 속성과 연결, 태그 문자열을 파싱하여 나타냄
  • 단방향 데이터 바인딩
<body>
    <div id="app">
        <div v-html="message"></div>
    </div>
</body>

<script>
    let model = { message: '<h1>Hello Vue3!</h2>' };
    let vm = Vue.createApp({
        name: "App",
        data() {
            return model;
        }
    }).mount('#app');
</script>

 


 

 v-bind 디렉티브

  • 요소의 속성을 바인딩
  • 단방향 데이터 바인딩
    • Vue 인스턴스의 데이터나 속성이 바뀌면 UI가 갱신됨
    • 화면에서 값을 변경하는 것은 데이터에 반영되지 않음
<body>
    <div id="app">
        <input type="text" v-bind:value="message">
        <br/>
        <img v-bind:src="imagePath">
    </div>
</body>
<script src="https://unpkg.com/vue"></script>
<script>
    let vm = Vue.createApp( {
        name : "App",
        data() {
            return {
                message : "v-bind 디렉티브",
                imagePath : "https://contactsvc.bmaster.kro.kr/photos/18.jpg"
            };
         }
    }).mount('#app');
</script>




 

 v-model 디렉티브

  • 양방향 데이터 바인딩
  • 주로 form요소 바인딩에 사용
  • html의 value 속성과 연동
<div id="app">
    <input type="text" v-model="name">
    <br />
    입력한 값: <span>{{name}}</span>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
    let vm = Vue.createApp({
        name: "App",
        data() {
            return { name: '' };  //line2에서 양방향 데이터 바인딩됨
        }
    }).mount('#app');
</script>

 

 

❗ ❗주의 사항 ❗ ❗

다중 선택 vs 단일 선택에 따라 데이터 형식 변동

다중 선택 : 배열

단일 선택 : 문자열

 

  <div>
        선택한 취미: {{hobby.join(',')}} <br />
        선택한 상품 분류: {{category}}
  </div>
----------------
        data() {
            return {
                hobby: [],
                category: ''
            };
        }

 

 

 

수식어(modifier)

v-model에 기능 추가 역할

  •  lazy
    • input에서 엔터를 치거나 포커스를 이동했을 떄 입력값과 속성을 동기화
    • <input type="text" v-model.lazy="name" />
  • number
    • 문자열을 숫자로 자동 형변환시켜 속성에 반영
    • <input type="text" v-model.number="num" />
  • trim
    • 문자열의 앞뒤 공백을 자동으로 제거
    • <input type="text" v-model.trim="message" />

 

 


 

v-show 디렉티브

  • 화면에 보여줄지 말지를 결정하는 디렉티브(HTML 요소를 생성하지만 화면에 보여주지는 않을 수 있음)
  • display 속성을 제어
<img v-show = "amount<0" ...

 

 v-if 디렉티브

  • 조건에 부합하지 않을 경우 요소를 생성하지 않음(화면 출력 없음)
 <img v-if="amount < 0" ...

 v-else, v-else if 디렉티브

<div id="app">
    잔고:<input v-model="balance" />
    <br/>
    회원님의등급:
    <span v-if="balance>1000000">Gold</span>
    <span v-else-if="balance>=500000">Silver</span>
    <span v-else-if="balance>=200000">Bronze</span>
    <span v-else="balance">Basic</span>
</div>

 

 

 


 

 v-for 디렉티브

  • 반복적인 데이터 렌더링
  • 형식(배열 사용시) : <태그명 v-for="변수in 배열" :key="id값">
<tr v-for="contact in contacts" :key="contact.no">

 

  • 형식(객체 사용시) : <태그명v-for="(val, key) in 객체" :key="key">
 <option v-for="(val, key) in regions" :value="key" :key="key">{{val}}</option>

 

 

인덱스 번호가 필요한 경우)

 

 

 

 

 template 태그 - 여러 요소를 묶어서 반복 렌더링

 <template v-for="(contact, index) in contacts" :key="contact.no">

 


 

 v-for 디렉티브와 key 특성

배열을 렌더링할 때 데이터 변경없이 위치만 바뀌는 경우

  • key 속성이 없으면 => 전부 다시 렌더링
  • key 속성이 있으면 => 위치만 변경 가능

❗key 특성에는 인덱스 번호가 아닌, 고유한 변경되지 않는 값 부여

 

 


 

 Proxy 객체

  • 데이터의 변경 사항 감시, 값 변경 시 렌더링 다시 유도
  • Vue 인스턴스에서 data 옵션으로 지정한 객체
  • data로 지정된 객체는 모두 Proxy로 래핑
  • 배열의 데이터를 변경하는 메서드들도 매핑되어 있어, 배열 내용 변경시 watcher에게 변경을 알려서 다시 렌더링 필요

 

 

 

❓궁금증❓
네트워크에서 배운 Proxy 서버의 Proxy와 유사한 개념인건가?
==> 
Vue에서 "프록시"는 JavaScript의 Proxy 객체를 기반으로 작동하는 개념으로,Vue의 반응형(Reactivity) 시스템을 구현하는 핵심 기술
중간에서 데이터를 가로채고 조작한다는 점에서 유사

 

2025/03/17~ 03/18 Git, GitHub 특강


프로젝트 작업 과정

 

1) 원격 저장소에서 레포지토리 가져와서 로컬에서 개발 후 PR 보내는 과정

//깃허브 레포지토리 가져오기 및 상태 확인 코드
git clone "깃허브 레포지토리 링크"
git status
git log --oneline
git log --oneline --graph


//새로운 브랜치 생성 후 이동
git checkout -b [branchName]   
git branch
git checkout [branch]


//깃허브의 내 작업 브랜치로 올리기
git add [커밋할 파일]
git commit -m "커밋 메세지"
git push origin [내가 작업한 브랜치 명]



//깃허브 들어가서 내 작업 브랜치-> main으로 PR 생성

 

 

2) 원격 저장소에 변경된 내용 내 로컬에 가져오기

//원격 저장소 main에서 로컬 저장소main으로 가져오기
git pull


//로컬 저장소 main에서 로컬 저장소 내 브랜치로 가져오기
git merge main  or
git pull origin main   or
git rabase main


//브랜치 삭제
git branch -D [브랜치 명]

 

[1] git merge main을 사용할 경우

내가 commit한 내역 말고도 main으로부터 merge한 커밋이 생성되어 있음
==> commit 내역이 더러워질 수 있음!!!


 


[2] git pull main을 사용할 경우
pull == git fetch + git merge를 수행하는 명령어

merge는 로컬에서 실행하는 병합 작업
pull은 원격 저장소에서 변경사항을 가져온 후 자동으로 병합 수행

[3] git rebase main을 사용할 경우


feature-branch의 모든 커밋을 main의 최신 상태 위로 다시 정렬
병합 커밋 없이 히스토리가 깔끔하게 정리됨
==> 그러나, main에 이미 푸시된 커밋을 rebase하면 팀원들이 pull할 때 충돌 발생 가능

 

 

2025/03/14(금)

 

MVVM 패턴

Model-View-ViewModel

  • 애플리케이션 로직과 UI의 분리를 위해 설계
  • 비즈니스 로직에세는 ViewModel의 상태 데이터만 변경하면 즉시 View에 반영
  • Model : 순수 데이터 자체
  • View : 화면 , HTML과 CSS로 작성
  • View Model : View의 실제 논리 및 데이터 흐름, 여러가지 형태로 구현될 수 있음( 변수, 함수 등), 순수한 데이터를 화면에 표현하기에 편하도록 가공해서 가진다.

MVVM 패턴

 

 

 

  • model에서 직접 데이터를 바꾸면 화면에 바뀌지 않음

 

 


 ES6

 

var, let, const 차이점 정리

호이스팅 : 변수와 함수 선언이 코드 실행 전에 메모리에 할당되는 것

 

var 특징

  • 함수 스코프(Function Scope)를 가짐 (블록 {}을 무시함)
  • 변수 선언이 호이스팅(Hoisting)되며, 초기화되지 않은 상태에서 undefined로 할당됨
  • 같은 변수 이름을 여러 번 재선언 가능

 

 let 특징

 

  • 블록 스코프(Block Scope)를 가짐 ({} 내부에서만 유효)
  • 변수 선언이 호이스팅되지만 초기화되지 않아 TDZ(Temporal Dead Zone, 일시적 사각지대) 발생
  • 같은 변수를 재선언할 수 없음
  • 재할당 가능

 

 

const 특징

 

  • let과 동일하게 블록 스코프(Block Scope)를 가짐
  • 호이스팅되지만 TDZ 발생
  • 재할당 불가능
  • 선언과 동시에 초기화가 반드시 필요

 

 


기본 파라미터 , 가변 파라미터

기본 파라미터(Default Parameter)

  • 함수 호출 시 인수를 생략했을 때 가지는 기본 값을 지정
  • 뒷부분에 지정, 중간에만 지정하는 것은 불가능

 

 

 

가변 파라미터(Rest Parameter)

  • 전달하는 파라미터의 개수를 가변적으로 적용
  • 매개변수 앞에 ... 연산자 지정
    • 전달된 인수를 매개변수로 매칭
    • 매칭되지 않은 인수를 모아 배열로 지정 후, 가변 파라미터로 전달
  • 1개만 지정 가능, 마지막 매개변수에만 지정 가능

 

 


화살표 함수

화살표 함수(Arrow Function, =>)는 ES6(ECMAScript 2015)에서 도입된 간결한 함수 표현식, 기존의 function을 활용한 함수보다 짧고 직관적인 문법 제공

 

 

기본 문법

const 함수이름 = (매개변수) => 표현식;
  • 중괄호 {} 없이 한 줄로 작성하면 해당 표현식이 자동으로 반환
  • return 키워드 생략 가능
  • 한 줄짜리 함수로 객체를 return 할 때는 중괄호로 꼭 묶어야 함. 묶지 않으면 undefined 에러 발생

 

 

여러 줄 함수인 경우

const 함수이름 = (매개변수) => {
    // 여러 줄 코드 가능
    return 결과;
};
  • 중괄호 {} 사용, return 명시

 

 

화살표 함수의 this 바인딩 차이

기존 function 함수는 호출 방식에 따라 this 가 동적으로 결정되지만, 화살표 함수는 this를 자신을 감싼 상위 스코프에서 가져온다. 👉 화살표 함수는 자신만의 this를 가지지 않음

 

 

일반함수 vs 화살표 함수 예제

const obj = {
    name: "kwon",
    regularFunction: function() {
        console.log("Regular:", this.name);
    },
    arrowFunction: () => {
        console.log("Arrow:", this.name);
    }
};

obj.regularFunction(); // "Regular: Alice"
obj.arrowFunction();   // "Arrow: undefined"

 

❗왜 arrowFunction()의 결과가 undefined일까?

  • regularFunction(): this가 obj를 가리킴.
  • arrowFunction(): this가 obj가 아니라 상위 스코프(전역 객체 또는 undefined)를 가리킴.

 

 

화살표 함수를 주로 사용하는 경우

1. 콜백 함수

2. 클래스 내부에서 this가 필요 없는 함수

3. 이벤트 리스너 내부에서 this가 필요한 경우

2025/3/13(목)

 

파일 관리_Path 모듈

  • 운영체제 간에 경로를 구분하는 구분자가 다른 불편 존재 => 경로 구분자를 통일하기 위해 사용
  • 경로를 나누거나 합치기 가능
  • 절대경로( `파일절대경로: ${__filename}` ), 상대 경로 존재
  • 경로 존재 여부로, 이름이 같은 내가 만든 모듈과 내장 모듈 구분 가능

 

 

주요 함수

Path 모듈 가져오기

const path = require('path');

 

 

경로 합치기

path.join(경로1,경로2,...);

 

 

경로만 추출하기 

path.dirname(경로);

 

 

파일 이름만 추출하기

path.basename(경로);

 

 

파일 이름만 추출하기(확장자 제외)

path.basename(경로, 확장자);

 

 

확장자 추출하기

path.extname(경로);

 

 

경로를 객체로 변환하기

=> 각각의 정보를 한번에 가져올 수 있음

path.parse(경로)

{
  root, // 루트 디렉터리
  dir,  // 디렉터리 경로
  base, // 파일명.확장명
  ext,  // 확장명
  name  // 파일명
}

 


FS 모듈

  • File System 모듈의 약자
  • 비동기 처리 방법에 따라 사용하는 함수가 다름
    • 동기 처리 함수
    • 콜백 처리 함수
    • Promise API
  • FS 모듈 가져오기 : const fs = require('fs');

 

1. 동기 처리

 

에러 체크는 try catch로 실행

파일 존재 여부 체크 : fs.existsSync(파일)

 

2. 비동기 처리

 

 

 

요약

                                  동기 처리                                비동기 처리
디렉터리 읽기 fs.readdirSync('./'); fs.readdir('./', (err, files) =>
파일 읽기 fs.readFileSync('./example.txt'); fs.readFile('./example.txt', 'utf-8', (err, data) =>
파일에 쓰기 fs.writeFileSync('./text-1.txt', data); fs.writeFile('./text-2.txt', data, (err) =>
기존 파일에  내용 추가하기 fs.writeFileSync('./text-1.txt', content, { flag: 'a' });
fs.appendFileSync(파일, 내용);
fs.appendFile('./text-2.txt', '\n\n 새로운 내용 추가', (err) =>
파일 삭제하기 fs.unlinkSync('./text-1.txt'); fs.unlink('./text-2.txt', (err) =>
디렉터리 만들기 fs.mkdirSync(경로 [, 옵션]) fs.mkdir('./test', (err) =>

fs.mkdir('./test2/test3/test4', { recursive: true }, (err) =>
디렉터리 삭제하기 fs.rmdirSync(경로 [, 옵션]) fs.rmdir('./test', (err) =>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2025/3/12(수)

 

자바스크립트의 비동기

  • 노드 프로그램은 서버에서 실행되므로 대부분의 명령을 비동기 처리
  • 자바스크립트의 기본 설정은 비동기식

 

비동기 처리란?

  • 시간이 걸리는 함수와 빨리 처리할 수 있는 함수가 섞여 실행 순서를 알 수 없을 떄
  • 함수들이 원하는 처리 순서에 맞게 프로그래밍하는 것

 


 

비동기 처리_1) 콜백 함수

함수 안에 또 다른 함수를 매개변수로 넘겨서 실행순서를 제어하는 방식

=> 함수를 실행할 때, 특정 동작이 끝난 후 실행될 함수를 전달하는 개념

function mainFunction(callback) {
    console.log("메인 함수 실행");
    callback(); // 전달받은 콜백 함수 실행
}

function myCallback() {
    console.log("콜백 함수 실행");
}

// mainFunction 실행 시 myCallback을 콜백 함수로 전달
mainFunction(myCallback);
실행 결과
-----------
메인 함수 실행
콜백 함수 실행

 

 

 

콜백 함수는 마지막 매개변수로

function order(coffee, callback) {
	//커피 주문
    //3초 기다린 후 콜백 실행
}

function display(result) {
	//커피 완료 표시
}

order("아메리카노", display); //display함수를 order함수의 매개변수로 전달

 

 

 

 

콜백 함수를 사용할 때 한번만 실행하고 끝난다면 함수 안에 익명 함수로 직접 작성 가능

function displayLetter() {
  console.log('A');
  setTimeout(() => {
    console.log('B');
    setTimeout(() => {
      console.log('C');
      setTimeout(() => {
        console.log('D');
        setTimeout(() => {
          console.log('stop!');
        }, 1000);
      }, 1000);
    }, 1000);
  }, 1000);
}

displayLetter();

 

콜백이 중첩될수록 코드가 복잡해짐 => 콜백 지옥

==> Promise를 사용하여 콜백 지옥 해결

 

 

 

 

비동기 처리_ 2) Promise(프라미스)

프라미스 객체 콜백 함수를 사용해서 실행 순서 제어

"어떤 작업이 끝나면 결과를 반환할 것을 약속하는 객체"

 

Promise의 3가지 상태
pending (대기 중) 비동기 작업이 아직 완료되지 않음
fulfilled (이행됨) 작업이 성공적으로 완료됨 (resolve())
rejected (거부됨) 작업이 실패함 (reject())

 

const myPromise = new Promise((resolve, reject) => {
    let success = true; // 성공 여부를 설정

    setTimeout(() => {
        if (success) {
            resolve("✅ 작업 성공!");
        } else {
            reject("❌ 작업 실패!");
        }
    }, 2000);
});

myPromise
    .then(result => console.log(result)) // 성공 시 실행
    .catch(error => console.error(error)) // 실패 시 실행
    .finally(() => console.log("🎯 작업 완료!"));
실행 결과
-----------
✅ 작업 성공!
🎯 작업 완료!

 

 

 

 

Promise 체이닝

여러개의 비동기 작업을 연결해서 실행

function getUser() {
    return new Promise(resolve => {
        setTimeout(() => resolve("👤 사용자 데이터"), 1000);
    });
}

function getPosts(user) {
    return new Promise(resolve => {
        setTimeout(() => resolve(`${user}의 게시글`), 1000);
    });
}

getUser()
    .then(user => getPosts(user))
    .then(posts => console.log(posts)) // "👤 사용자 데이터의 게시글"
    .catch(error => console.error("❌ 오류 발생:", error));

 

Promise 역시 체이닝을 사용해서 연결을 계속하면 콜백 지옥처럼 코드가 복잡해질 수 있음!

 

 

 

 

비동기 처리_3) async/await

  • Promise를 더 쉽게 사용할 수 있도록 도와주는 최신 문법
  • 콜백 함수나 .then() 체이닝 없이 가독성이 뛰어난 비동기 코드를 작성 가능
async 비동기 함수를 정의하는 키워드
await 비동기 함수 내에서 Promise가 완료될 때까지 기다림

 

 

 async function init() {
 	try {
 		const response = await fetch('https://jsonplaceholder.typicode.com/users');
 		const users = await response.json();
 		console.log(users);
 	} catch (err) {
 		console.error(err);
 	}
 }
 
 init();

 

 


노드의 모듈

  • 노드에서는 대부분의 기능을 모듈 단위로 나누어 작성
  • 기능별로 만들어 놓은 함수

 

 

모듈의 종류 3가지

1)  내장 모듈(노드가 제공)

2)  내가 만든 모듈

3)  서드파티 모듈

 

 

 

모듈의 사용 이유

  • 코드의 재사용화, 라이브러리화를 위해

CommonJS 모듈 시스템

✅ module.exports

require()

// math.js (CommonJS)
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// 모듈을 내보내는 방법 (객체 형태로 여러 개 내보낼 수 있음)
module.exports = subtract;
module.exports = { add, subtract };
// app.js (CommonJS)
const math = require('./math'); // 모듈 가져오기

console.log(math.add(5, 3)); // 8
console.log(math.subtract(10, 4)); // 6

 

 

ES 모듈 시스템

 

✅ 모듈 내보내기 (export)

// math.mjs (ES 모듈)
export const add = (a, b) => a + b;
-----------------------------------------
const goodbye = (name) => {
    console.log(`${name}님, 안녕히 가세요`);
}
export default goodbye;

 

 

 

✅ 모듈 가져오기 (import)

// app.mjs (ES 모듈)
import { add, subtract } from './math.mjs';

console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

 

+ Recent posts