목차(클릭하세요)
1. JS만의 함수 특징
1-1. 함수와 호이스팅
•
호이스팅(Hoisting)은 변수와 함수 선언이 해당 스코프의 최상단으로 "끌어올려지는" JavaScript의 독특한 동작
함수 선언문 호이스팅
// 함수 호출이 선언보다 먼저 와도 동작함
sayHello(); // "안녕하세요!" - 정상 동작
function sayHello() {
    console.log("안녕하세요!");
}
JavaScript
복사
•
이게 왜 될까? 
◦
자바스크립트는 코드를 실행하기전 준비단계를 거치는데, 이 때 중첩함수가 아닌 함수들은 모두 찾아 미리 생성해두는 자바스크립트의 괴랄한 특성때문 인듯
•
무슨 장점이라도?
◦
함수 선언의 위치를 강제하지 않아 더 유연한 프로그래밍이 가능해짐
1-2.함수 표현식
•
함수를 변수에 할당하는 방식으로, 함수를 값처럼 다룰 수 있음
// 함수 선언문
function declaration() {
    return "선언문";
}
// 함수 표현식
const expression = function() {
    return "표현식";
};
// 명명된 함수 표현식
const namedExpression = function myFunc() {
    return "명명된 표현식";
};
JavaScript
복사
[함수표현식에서 무슨 차이?]
•
함수 표현식 = 기본적으로 익명 함수를 변수/상수에 할당하는 방식.
•
명명된 함수 표현식 = 이름이 붙은 함수 표현식 (주로 디버깅 편의를 위해 사용).
1-3.화살표 함수
•
ES6에서 도입된 간결한 함수 표현 방식
•
익명함수를 매우 간결하게 작성할 때 사용
•
[사용법]
let funcA = (매개변수)  => 반환값;
JavaScript
복사
// 기본 화살표 함수
const add = (a, b) => {
    return a + b;
};
// 한 줄 함수 - return 생략 가능
const multiply = (a, b) => a * b;
// 매개변수가 하나일 때 - 괄호 생략 가능
const square = x => x * x;
// 매개변수가 없을 때는 괄호 생략 불가능
const sayHello = () => "안녕하세요!";
JavaScript
복사
[화살표 함수 사용Tip]
•
화살표 함수(()=>{})를 변수에 담을 때는 let보다 const를 더 자주 사용
•
이유: 대부분의 경우 함수 정의가 한 번 정해지면 바뀌지 않으므로 const가 적합
const add = (a, b) => a + b; // 안전
// add = 100; ❌ 에러 발생
JavaScript
복사
1-3.함수 연습문제
//코드샌드박스에서 출력을 위한 기본 코드
import "./styles.css";
// HTML 먼저 생성
document.getElementById("app").innerHTML = `
<h1 id="title">🎮 게임 함수 마스터</h1>
<p id="change">빈칸(???)을 채워서 게임을 완성하세요!</p>
<div id="test" style="white-space: pre-line;"></div>
`;
let result = "";
// === 1. 게임 초기화 (함수 호이스팅) ===
result += "=== 1. 게임 초기화 ===\n";
// 사용자 이름 입력받기
??? playerName = prompt("플레이어 이름을 입력하세요:") ??? "익명";  // 값이 변할 수 있는 변수 키워드, 기본값을 제공하는 연산자
// 함수 선언 전에 호출 가능! (호이스팅)
let gameStart = startGame(playerName);                  
result += gameStart + "\n";
??? startGame(name) {                                   // 호이스팅이 가능한 함수 선언 방식
    return `${name}님의 모험이 시작됩니다!`;
}
result += "\n";
// === 2. 게임 플레이 (함수 표현식) ===
result += "=== 2. 게임 플레이 ===\n";
// 몬스터 전투 함수 (함수 표현식)
??? battleMonster = function(playerLevel, monsterLevel) {  // 변하지 않는 변수에 함수를 저장
    ??? damage = playerLevel * 10 - monsterLevel * 5;      // 함수 내부에서 계산값을 저장할 변수
    return damage > 0 ? "승리!" : "패배...";
};
// 아이템 획득 함수 (화살표 함수)
??? getItem = (itemName) ??? `${itemName} 획득!`;        // 짧은 함수를 간단하게 쓰는 방법, 화살표 기호
let battle1 = battleMonster(5, 3);
let battle2 = battleMonster(2, 4);
let item = getItem("마법검");
result += `전투 1: ${battle1}\n`;
result += `전투 2: ${battle2}\n`;
result += `아이템: ${item}\n\n`;
// === 3. 게임 결과 (화살표 함수 활용) ===
result += "=== 3. 게임 결과 ===\n";
let scores = [100, 250, 180, 320, 90];
// 고득점만 필터링 (화살표 함수)
??? highScores = scores.???(score ??? score >= 200);      // 조건에 맞는 요소만 걸러내는 배열 메서드
// 점수 합계 계산 (화살표 함수)
??? total = scores.???(???sum, score) ??? sum + score, 0); // 배열을 하나의 값으로 축약하는 메서드, 누적값 매개변수
// 최종 등급 계산 (화살표 함수)
??? getGrade = (score) ??? score >= 300 ??? "S" ??? score >= 200 ??? "A" ??? "B"; // 조건에 따라 값을 선택하는 연산자
let finalGrade = getGrade(total);
result += `${playerName}님의 결과:\n`;
result += `고득점: ${highScores.join(", ")}\n`;
result += `총점: ${total}\n`;
result += `최종 등급: ${finalGrade}\n`;
document.getElementById("test").textContent = result;
JavaScript
복사
2. 객체와 배열
2-1. 객체 생성과 프로퍼티(with 리터럴??)
•
객체는 키(key)와 값(value)의 쌍으로 데이터를 저장하는 JavaScript의 핵심 데이터 구조
// 기본 객체 생성
const student = {
    name: "양파고",
    age: 17,
    school: "한국고등학교",
    isStudent: true
};
// 중첩 객체
const player = {
    name: "철수",
    stats: {
        level: 15,
        hp: 100,
        mp: 50
    },
    inventory: ["검", "방패", "포션"]
};
JavaScript
복사
[리터럴이란?]
•
literal = “값 그 자체를 코드에 직접 적어 표현한 것”
•
즉, 프로그래머가 코드에 직접 써넣은 값을 뜻함
•
예시
◦
숫자 리터럴: 10, 3.14
◦
문자열 리터럴: "hello", 'world'
◦
불리언 리터럴: true, false
•
객체 리터럴이란?
◦
중괄호 {}를 사용해 객체를 직접 정의하는 문법
•
객체 리터럴과 반대되는 개념이 표현식이라 생각하면 편함
◦
new Object() → 객체를 만드는 표현식(expression)
◦
{ name: "A" } → 직접 속성과 값을 적어 객체를 만드는 리터럴(literal)
구분  | 코드 예시  | 설명  | 사용 빈도  | 
리터럴  | const obj = { name: "민수", age: 17 };  | 직접 {} 안에 값 써서 객체 생성  | ★★★★★  | 
표현식 - 생성자 함수 호출  | new Student("민수", 17)  | 함수 정의 후 new로 호출  | ★★★☆☆  | 
표현식 - new Object()  | new Object()  | 내장 생성자 호출 후 속성 추가  | ★☆☆☆☆  | 
[생성자 함수로 객체생성하기]
function Student(name, age) {
    this.name = name;
    this.age = age;
    this.study = function() {
        return `${this.name}이(가) 공부 중입니다.`;
    };
}
const student1 = new Student("민수", 17);
JavaScript
복사
2-2.객체 프로퍼티 다루기
[프로퍼티란?]
•
객체(Object)는 키(key)와 값(value)의 쌍으로 이루어짐.
•
이때 키를 프로퍼티 이름(property name), 값을 프로퍼티 값(property value)라고 부름.
•
즉, 프로퍼티 = 키 + 값 쌍 전체를 가리킴
1.
프로퍼티의 특징
•
동적 추가: 언제든지 새로운 프로퍼티 추가 가능
•
다양한 타입: 문자열, 숫자, 불리언, 함수, 객체 등 모든 타입 저장 가능
•
메서드: 객체 내부의 함수를 메서드라고 함
2.
프로퍼티의 접근방법은 크게 2가지: 점 표기법, 대괄호 표기법
•
점표기법
const user = {
    name: "양파고",
    age: 17,
    email: "yangphago@example.com"
};
console.log(user.name);    // "양파고"
console.log(user.age);     // 17
JavaScript
복사
•
대괄호 표기법
console.log(user["name"]);           // "양파고"
console.log(user["age"]);            // 17
// 변수를 키로 사용 가능
const key = "email";
console.log(user[key]);              // "yangphago@example.com"
// 공백이나 특수문자가 있는 키
const game = {
    "player name": "철수",
    "high-score": 1500
};
console.log(game["player name"]);    // "철수"
JavaScript
복사
3.
프로퍼티 추가&수정하기
const car = {
    brand: "현대",
    model: "아반떼"
};
// 프로퍼티 추가
car.year = 2023;
car["color"] = "흰색";
// 프로퍼티 수정
car.model = "소나타";
JavaScript
복사
4.
프로퍼티 삭제하기
delete car.color;
console.log(car.color);  // undefined
JavaScript
복사
2-3.배열과 배열 인덱스
•
배열은 순서가 있는 데이터의 집합으로, 인덱스를 통해 요소에 접근
•
자바스크립트의 배열은 단순히 순서를 가진 특별한 객체
◦
인덱스(0, 1, 2, …)가 키처럼 작동하고,
◦
배열 객체 안에는 length 같은 프로퍼티와 push, pop 같은 메서드가 기본 내장돼 있음
const games = ["롤토체스", "리그오브레전드"];
// 끝에 추가/제거
games.push("발로란트");           // ["롤토체스", "리그오브레전드", "발로란트"]
games.pop();                     // "발로란트" 제거
// 앞에 추가/제거
games.unshift("오버워치");        // ["오버워치", "롤토체스", "리그오브레전드"]
games.shift();                   // "오버워치" 제거
JavaScript
복사
2-4.date객체와 날짜
•
Date 객체는 날짜와 시간을 다루는 JavaScript의 내장 객체
const now = new Date();
// 기본 문자열 변환
console.log(now.toString());        // 전체 날짜 시간
console.log(now.toDateString());    // 날짜만
console.log(now.toTimeString());    // 시간만
// 로케일 형식
console.log(now.toLocaleDateString("ko-KR"));     // "2025. 3. 7."
console.log(now.toLocaleTimeString("ko-KR"));     // "오후 2:30:45"
//date함수의 사용법
function formatDate(date) {
    // 1. 연도(yyyy) 추출
    const year = date.getFullYear();
    // 2. 월(mm) 추출 → getMonth()는 0~11을 반환하므로 +1
    //    padStart(2, '0')로 두 자리 맞추기 (예: 3 → 03)
    const month = String(date.getMonth() + 1).padStart(2, '0');
    // 3. 일(dd) 추출 → padStart로 두 자리 맞춤
    const day = String(date.getDate()).padStart(2, '0');
    // 4. yyyy-mm-dd 형식의 문자열로 반환
    return `${year}-${month}-${day}`;
}
JavaScript
복사
2-5.연습문제
객체 생성:
•
const aespa = {}
프로퍼티 접근:
•
점 표기법: aespa.groupName
•
대괄호 표기법: aespa["hit2022"]
배열 메서드:
•
filter(), map(), reduce(), length
Date 객체:
•
new Date(), getFullYear(), getMonth(), getDate()
//코드샌드박스에서 출력을 위한 기본 코드
import "./styles.css";
// HTML 먼저 생성
document.getElementById("app").innerHTML = `
<h1 id="title">🎵 aespa 히트곡 관리 시스템</h1>
<p id="change">빈칸(???)을 채워서 aespa 정보 시스템을 완성하세요!</p>
<div id="test" style="white-space: pre-line;"></div>
`;
let result = "";
// === 1. 객체 리터럴로 aespa 기본 정보 생성 ===
result += "=== 1. aespa 기본 정보 ===\n";
??? aespa = {                                // 변경되지 않는 객체를 선언할 때 사용하는 키워드
  groupName: "aespa",
  debutDate: new Date("2020-11-17"),
  company: "SM Entertainment",
  members: ["카리나", "지젤", "윈터", "닝닝"],
};
result += `그룹명: ${aespa.???}\n`;          // 객체의 속성에 접근하는 방법 중 하나
result += `소속사: ${aespa.???}\n\n`;        // 위와 같은 방식으로 접근
// === 2. 히트곡 프로퍼티 추가 (점 표기법) ===
result += "=== 2. 히트곡 추가 (점 표기법) ===\n";
// 점 표기법으로 히트곡 추가
aespa.??? = "Black Mamba";                  // 새로운 속성 이름을 정해보세요
aespa.??? = [];                             // 여러 곡을 담을 수 있는 데이터 구조
aespa.hit.???("Next Level");                // 배열에 요소를 추가하는 메서드
aespa.hit.???("Savage");                    // 같은 메서드를 사용
aespa.hit.???("위 플래쉬");                  // 계속 같은 메서드
result += `데뷔곡: ${aespa.debut_song}\n`;
result += `히트곡 리스트: ${aespa.hit}\n`;
// === 3. 추가 정보 (대괄호 표기법) ===
result += "\n=== 3. 추가 정보 (대괄호 표기법) ===\n";
// 대괄호 표기법으로 정보 추가
aespa["???"] = aespa.members.???;           // 앨범 수와 관련된 속성명, 배열의 크기를 알 수 있는 속성
result += `발매 앨범의 갯수: ${aespa.total_albums}\n\n`;
// === 4. 인기 멤버 순서에 따라 배열로 변환 ===
result += "=== 4. 인기멤버 배열 관리 ===\n";
// 인기순으로 멤버 재배열
??? superstar_number = [                    // 변경되지 않을 배열 선언
  aespa.members[???],                       // 첫 번째 멤버
  aespa.members[???],                       // 세 번째 멤버
  aespa.members[???],                       // 네 번째 멤버
  aespa.members[???],                       // 두 번째 멤버
];
// 가장 인기 있는 멤버 (첫 번째)
??? mostPopular = superstar_number[???];    // 변경되지 않을 변수, 첫 번째 요소
result += `최고의 멤버: ${mostPopular}\n\n`;
// === 5. Date 객체를 활용한 기념일 계산 ===
result += "=== 5. 데뷔 기념일 계산 ===\n";
??? today = new Date();                     // 오늘 날짜를 담을 변수
??? debutYear = aespa.debutDate.???();      // 연도를 가져오는 메서드
??? currentYear = today.???();              // 현재 연도를 가져오는 메서드
??? yearsActive = currentYear - debutYear;  // 활동 기간 계산
// 올해 데뷔 기념일
??? thisYearAnniversary = new Date(         // 올해 기념일 날짜 객체
  currentYear,
  aespa.debutDate.???(),                    // 월을 가져오는 메서드
  aespa.debutDate.???()                     // 일을 가져오는 메서드
);
// 기념일까지 남은 일수
??? daysUntilAnniversary = Math.ceil(       // 값이 변경될 수 있는 변수
  (thisYearAnniversary - today) / (1000 * 60 * 60 * 24)
);
// 기념일이 지났다면 내년 기념일 계산
if (daysUntilAnniversary < 0) {
  thisYearAnniversary.???(currentYear + 1); // 연도를 설정하는 메서드
  daysUntilAnniversary = Math.ceil(
    (thisYearAnniversary - today) / (1000 * 60 * 60 * 24)
  );
}
result += `데뷔: ${debutYear}년\n`;
result += `활동 기간: ${yearsActive}년\n`;
result += `다음 기념일까지: ${daysUntilAnniversary}일\n\n`;
document.getElementById("test").textContent = result;
JavaScript
복사
3. 비동기 처리
→ fetch() 같은 HTTP 요청은 시간이 오래 걸리므로 비동기로 처리해야 UI가 멈추지 않음.
•
동기(Synchronous): 작업이 순서대로 하나씩 완료되어야 다음 작업을 진행
•
비동기(Asynchronous):  작업을 시작하고 완료를 기다리지 않고 다음 작업을 바로 진행
구분  | 동기(Sync)  | 비동기(Async)  | 
실행 흐름  | 한 줄 끝나야 다음 줄 실행  | 오래 걸리는 작업은 백그라운드로 넘기고, 나머지 코드 먼저 실행  | 
장점  | 코드 이해가 단순  | UI 멈춤 방지, 효율적 리소스 활용  | 
예시  | alert("hi")  | fetch(), setTimeout()  | 
3-1. 동기와 비동기
은행창구 = 동기 처리
•
한 사람의 업무가 끝나야 다음 손님이 처리 가능
카페 = 비동기 처리
•
주문받고 나서 음료가 나올 때까지 기다리는 동안, 다른 손님의 주문도 처리 가능
3-2.비동기함수의 실제 사용법(초급)
1.
자바스크립트는 setTimeout 메서드를 이용해 비동기적 처리 가능
console.log("주문 접수");
setTimeout(() => {
  console.log("커피 준비 완료 ☕");
}, 2000); // 2초 뒤 실행
console.log("다른 손님 주문 받는 중...");
JavaScript
복사
2.
조금 더 복잡한 형태의 setTimeout 이용
function processOrder() {
    console.log("주문 접수");
    
    setTimeout(() => {
        console.log("재료 준비 완료");
        
        setTimeout(() => {
            console.log("조리 완료");
            
            setTimeout(() => {
                console.log("서빙 완료");
            }, 2000);
        }, 3000);
    }, 1000);
}
processOrder()
JavaScript
복사
3-2.비동기함수의 실제 사용법(고급)
1.
3가지 상태: 대기, 성공, 실패
•
대기(Pending): 아직 결과가 나오지 않음
•
성공(Fulfilled): 작업이 성공적으로 완료됨
•
실패(Rejected): 작업이 실패함
2.
실행함수가 제공받는 2개의 매개변수: resolve, reject 
•
resolve: 작업 성공 시 호출하는 함수
•
reject: 작업 실패 시 호출하는 함수
•
Promise를 만들 때 resolve만 쓰고 reject는 생략하는 게 가능
•
개발자가 가독성을 위해 이름을 줄일 수도 있음 →
•
resolve → res,        reject → rej
const myPromise = new Promise((resolve, reject) => {
    // resolve: 성공했을 때 호출하는 함수
    // reject: 실패했을 때 호출하는 함수
});
const myPromise = new Promise((res, rej) => {
  const num = Math.random(); // 0~1 사이 난수
  if (num > 0.5) {
    res(`✅ 성공! 난수=${num}`);
  } else {
    rej(`❌ 실패! 난수=${num}`);
  }
});
myPromise
  .then(msg => console.log("성공:", msg))
  .catch(err => console.log("실패:", err));
JavaScript
복사
3.
프로미스 객체를 활용한 예시
// Promise 생성
function fetchUserData(userId) {
    return new Promise((resolve, reject) => {
        // 실제로는 서버 요청이지만 시뮬레이션
        setTimeout(() => {
            if (userId > 0) {
                resolve({
                    id: userId,
                    name: "양파고",
                    email: "yangphago@example.com"
                });
            } else {
                reject(new Error("유효하지 않은 사용자 ID"));
            }
        }, 1000);
    });
}
// Promise 사용
fetchUserData(123)
    .then(userData => {
        console.log("사용자 정보:", userData);
    })
    .catch(error => {
        console.log("오류 발생:", error.message);
    });
JavaScript
복사
[참고] settimeout메서드를 쓰는 것과 프로미스 객체를 사용하는 것의 차이?
1.
setTimeout 메서드
•
타이머 기반 비동기 처리
•
일정 시간이 지난 후 특정 코드를 실행하는 용도
•
단순한 이벤트 지연/예약 실행에 적합
•
콜백(callback) 방식으로 동작
2.
Promise 객체
•
Promise는 비동기 작업의 완료(성공) 또는 실패를 나타내는 객체로, 그 결과값을 나중에 사용할 수 있게 해줌
•
네트워크 요청, 파일 읽기/쓰기 같은 결과가 나중에 도착하는 작업을 처리할 때 사용
•
세 가지 상태(Pending → Fulfilled/Rejected)를 가짐
•
then, catch, finally 체이닝 가능 → 가독성 좋고 에러 처리 쉬움
◦
.then() → 작업 성공 시 실행할 콜백 등록
◦
.catch() → 작업 실패 시 실행할 콜백 등록
◦
.finally() → 성공/실패와 관계없이 마지막에 실행할 콜백 등록
[JS의 콜백함수?]
매개변수로 함수 객체를 전달해서 호출 함수 내에서 매개변수 함수를 실행하는 것
 콜백 함수란 파라미터로 일반적인 변수나 값을 전달하는 것이 아닌 함수 자체를 전달하는 것
어차피 매개변수에 함수를 전달해 일회용으로 사용하기 때문에 굳이 함수의 이름을 명시할 필요가 없어 보통 콜백 함수 형태로 함수를 넘겨줄때 함수의 이름이 없는 '익명 함수' 형태로 넣어주게 됨
function sayHello(name, callback) {
    const words = '안녕하세요 내 이름은 ' + name + ' 입니다.';
    
    callback(words); // 매개변수의 함수(콜백 함수) 호출
}
sayHello("양파고", function printing(name) {
	console.log(name); // 안녕하세요 내 이름은 인파 입니다.
});
JavaScript
복사
•
화살표 함수모양의 콜백함수
function sayHello(callback) {
  let name = "phago";
  callback(name); // 콜백 함수 호출
}
// 익명 화살표 콜백 함수
sayHello((name) => {
  console.log("Hello, " + name);
}); // Hello, Alice
JavaScript
복사
3.
체이닝 방식의 비동기 처리
메서드를 연속적으로 연결해서 호출하는 개념, 체이닝은 약간의 순차 실행 느낌
const order = new Promise((resolve, reject) => {
  const stock = true;
  if (stock) resolve("커피 준비 완료 ☕");
  else reject("재고 없음 ❌");
});
order
  .then(msg => {
    console.log("성공:", msg);
    return "손님께 전달 완료 ✅";   // 다음 then으로 값 전달
  })
  .then(nextMsg => {
    console.log(nextMsg);
  })
  .catch(err => {
    console.log("실패:", err);
  })
  .finally(() => {
    console.log("작업 종료 🚪");
  });
JavaScript
복사
4.
병렬처리 방식의 비동기처리
// 각각의 독립적인 작업들을 별도의 Promise로 분리
const checkStock = new Promise((resolve, reject) => {
    const stock = true;
    if (stock) resolve("재고 확인 완료 ✅");
    else reject("재고 없음 ❌");
});
const prepareCoffee = new Promise((resolve) => {
    setTimeout(() => resolve("커피 준비 완료 ☕"), 1000);
});
const preparePackaging = new Promise((resolve) => {
    setTimeout(() => resolve("포장 준비 완료 📦"), 800);
});
const notifyCustomer = new Promise((resolve) => {
    setTimeout(() => resolve("손님 호출 완료 📢"), 500);
});
// Promise.all로 병렬 처리
Promise.all([checkStock, prepareCoffee, preparePackaging, notifyCustomer])
    .then(results => {
        console.log("모든 작업 완료:");
        results.forEach(result => console.log(result));
        console.log("주문 처리 완료 🎉");
    })
    .catch(err => {
        console.log("실패:", err);
    })
    .finally(() => {
        console.log("작업 종료 🚪");
    });
JavaScript
복사
[어려움]
•
체이닝 = 비동기 순차 실행
•
병렬 = 비동기 동시 실행
•
체이닝은 "비동기 + 한 줄씩 기다리며 처리"
•
병렬은 "비동기 + 여러 줄을 동시에 실행"
3-4.연습문제
[중요개념 돌아보기]
1.
resolve (Promise 성공 처리)
2.
task (타이머 함수)
3.
await (비동기 작업 기다리기)
4.
Promise.all (여러 비동기 작업을 동시에 처리)
5.
async (비동기 함수 선언)
// 기본 셋업
import "./styles.css";
document.getElementById("app").innerHTML = `
<h1>🍽️ 저녁식사 준비 - 비동기 실습</h1>
<div id="test" style="white-space: pre-line;"></div>
`;
// ??? 문자열을 받아 특정 영역에 출력하고 줄바꿈("\n")을 추가하는 함수
function write(msg) {
  document.getElementById("test").textContent += msg + "\n";
}
// 공통 타이머 작업 (ms 뒤 ??? 호출)
// 힌트: 일정 시간이 지난 뒤 Promise를 성공 상태로 바꿔주는 함수
function task(taskName, ms) {
  return new Promise(function (????) {
    setTimeout(function () {
      ????(taskName); // 일정 시간 뒤 작업 이름 반환
    }, ms);
  });
}
// 개별 작업 실행 + 시간 측정/출력
async function doTask(taskName, ms) {
  const s = performance.now();
  await ????(taskName, ms); // 힌트: 위에서 만든 "타이머 함수" 호출
  write(`${taskName} 성공 (${((performance.now() - s) / 1000).toFixed(2)}s)`);
}
// 시간 상수
const T_CHICKEN = 5000; 
const T_SALAD = 3000; 
const T_TABLE = 2000; 
// 1) 체이닝(순차)
// ??? 키워드를 사용해 작업을 순서대로 기다리며 실행
async function runChaining() {
  write("=== 체이닝 (순차 실행) ===");
  const t0 = performance.now();
  await ????("치킨", T_CHICKEN);
  await ????("샐러드", T_SALAD);
  await ????("상차리기", T_TABLE);
  write(
    `총 실제 소요 시간: ${((performance.now() - t0) / 1000).toFixed(2)}s\n`
  );
}
// 2) 병렬(동시)
// 여러 비동기 작업을 동시에 실행하려면 ??? 메서드 사용
async function runParallel() {
  write("=== 병렬 (동시 실행) ===");
  const t0 = performance.now();
  await ????.????([
    doTask("치킨", T_CHICKEN),
    doTask("샐러드", T_SALAD),
    doTask("상차리기", T_TABLE),
  ]);
  write(
    `총 실제 소요 시간: ${((performance.now() - t0) / 1000).toFixed(2)}s\n`
  );
}
// 실행 (순서 보장)
// ??? 함수 표현식 → 비동기 실행 흐름 제어 가능
(???? () => {
  await runChaining();
  await runParallel();
})();
JavaScript
복사