면접카타 3,4번 - TIL250211
3. async/await 이란 무엇인지 설명해주세요.
답변:
async/await는 JavaScript에서 비동기 코드를 보다 읽기 쉽게 작성할 수 있도록 도와주는 문법입니다.
async 키워드를 함수 앞에 붙이면 해당 함수는 자동으로 Promise를 반환하는 비동기 함수가 됩니다.
await 키워드는 Promise가 처리될 때까지 기다렸다가 그 결과를 반환하도록 만듭니다.
이 방식은 기존의 then/catch 체인보다 코드 가독성을 높이고, 동기 코드처럼 작성할 수 있도록 도와줍니다.
예제 코드:
async function fetchData() {
try {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
위 코드는 fetch를 사용해 데이터를 가져오는 비동기 함수입니다.
await를 사용하면 fetch의 응답을 받을 때까지 기다린 후, 데이터를 JSON으로 변환하는 작업을 수행합니다.
에러가 발생하면 try-catch 문을 활용해 예외 처리를 할 수 있습니다.
추가질문 예시
1. async/await과 Promise.then() 방식의 차이점은 무엇인가요?
차이점 정리:
구분 | async/await | Promise.then() |
코드 가독성 | 동기 코드처럼 자연스럽게 읽힘 | then() 체인이 길어지면 가독성 저하 |
에러 처리 | try-catch 블록 사용 가능 | .catch()를 사용하여 에러 처리 |
실행 방식 | await은 Promise의 결과를 기다렸다가 반환 | then()은 콜백을 사용하여 다음 작업을 수행 |
병렬 실행 | 기본적으로 순차 실행 (await이 실행을 차단) | .then() 체인은 병렬 실행 가능 |
예제 비교
✅ async/await 방식 (가독성 좋음)
async function fetchData() {
try {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
✅ Promise.then() 방식 ( .then() 체인 으로 병렬실행가능)
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
결론: async/await은 코드가 깔끔하고 이해하기 쉬운 반면, Promise.then()은 병렬 실행 시 유리할 수 있음.
2. async 함수 내부에서 await을 여러 번 사용할 때 성능 문제가 발생할 수 있는 이유는?
await은 다음 줄의 코드 실행을 일시 중단(blocking) 하기 때문에, 여러 개의 await을 순차적으로 실행하면 성능 저하가 발생할 수 있습니다.
비효율적인 코드 (순차 실행)
async function fetchData() {
let user = await fetch('/api/user'); // 1번째 요청
let posts = await fetch('/api/posts'); // 2번째 요청 (1번째 끝난 후 실행)
let comments = await fetch('/api/comments'); // 3번째 요청 (2번째 끝난 후 실행)
}
위 코드는 각 요청이 끝날 때까지 기다리므로 실행 시간이 길어짐.
효율적인 코드 (Promise.all()을 사용한 병렬 실행)
async function fetchData() {
let [user, posts, comments] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts'),
fetch('/api/comments')
]);
}
Promise.all()을 사용하면 세 요청이 동시에 실행되어 속도가 빨라짐.
결론: await을 반복적으로 사용하면 불필요한 순차 실행이 발생하여 성능이 저하될 수 있으므로, 동시 실행이 가능한 경우 Promise.all()을 활용하는 것이 좋음.
3. Promise.all()을 async/await과 함께 사용할 수 있나요? 어떻게 사용하나요?
네, Promise.all()을 async/await과 함께 사용하면 여러 개의 비동기 작업을 병렬로 실행할 수 있음.
사용 예시:
async function fetchMultipleData() {
try {
let [user, posts, comments] = await Promise.all([
fetch('/api/user').then(res => res.json()),
fetch('/api/posts').then(res => res.json()),
fetch('/api/comments').then(res => res.json())
]);
console.log(user, posts, comments);
} catch (error) {
console.error('Error fetching data:', error);
}
}
Promise.all()의 장점:
- 모든 요청을 동시에 실행하여 빠른 응답 가능
- 단, 하나라도 실패하면 전체가 실패하므로 에러 핸들링이 중요
4. Hoisting이란 무엇인지 설명해주세요.
답변:
Hoisting(호이스팅)이란 JavaScript에서 변수 및 함수 선언이 코드 실행 전에 최상단으로 끌어올려지는 것처럼 동작하는 현상을 말합니다.
예제 코드:
console.log(name); // undefined
var name = "Alice";
위 코드가 실행되면 JavaScript는 다음과 같이 해석합니다.
var name;
console.log(name); // undefined
name = "Alice";
따라서 변수 name이 선언되었지만 초기화되지 않았기 때문에 undefined가 출력됩니다.
1. Hoisting(호이스팅)이란
Hoisting(호이스팅)은 컴파일 단계에서 함수와 변수 선언을 렉시컬 환경(Lexical Environment)에 등록하여 실행 컨텍스트가 생성될 때 미리 메모리에 할당되어 변수를 선언하기 전에 사용하더라도 JavaScript 엔진이 선언을 코드의 최상단으로 이동시킨 것처럼 처리합니다.
렉시컬 환경에서의 변수 등록 차이
- var x → 렉시컬 환경에 x: undefined로 저장됨 (Hoisting 후 초기화됨)
- let y, const z → 렉시컬 환경에는 등록되지만 초기화되지 않아 TDZ(Temporal Dead Zone)에 있음)
※ 렉시컬 환경
렉시컬 환경은 크게 두 가지 구성 요소로 이루어져 있어.
- 환경 레코드(Environment Record)
- 현재 실행 중인 스코프(범위) 내에서 선언된 변수, 함수, 클래스 등의 식별자와 그 값을 저장하는 객체
- 외부 렉시컬 환경(Outer Lexical Environment Reference)
- 현재 실행 컨텍스트(Execution Context)에서 외부 스코프를 참조할 수 있도록 연결하는 역할
- 즉, 상위 스코프(부모 환경)로 접근하는 체인을 형성함 (스코프 체인, Scope Chain)
2. 변수 선언 방식에 따른 Hoisting 차이
선언 방식 | Hoisting 발생 여부 | 값 할당 이전 접근 시 결과 | TDZ(Temporal Dead Zone) |
var | O (호이스팅됨) | undefined 출력 | X (존재하지 않음) |
let | O (호이스팅됨) | ReferenceError 발생 | O |
const | O (호이스팅됨) | ReferenceError 발생 | O |
📌 설명:
- var은 Hoisting 후 undefined로 초기화되므로 접근 가능
- let, const는 Hoisting되지만 초기화되지 않아 TDZ(일시적 사각지대)에 존재하며, 접근 시 ReferenceError 발생
✅ 예제 코드
console.log(a); // undefined
var a = 10;
console.log(b); // ReferenceError (TDZ에 있음)
let b = 20;
3. 함수와 클래스의 Hoisting 차이
선언 방식 | Hoisting 발생 여부 | 선언 전 호출 가능 여부 |
함수 선언식 (function foo() {}) | O | O (선언 전에 호출 가능) |
함수 표현식 (const foo = function() {}) | X | X (선언 전에 호출 불가능) |
클래스 선언식 (class Foo {}) | O | X (TDZ로 인해 호출 불가능) |
클래스 표현식 (const Foo = class {}) | X | X (선언 전에 호출 불가능) |
📌 설명:
- 함수 선언식(function)은 Hoisting되어 선언 전에 호출 가능
- 함수 표현식(const foo = function() {})과 클래스 선언(class Foo {})은 TDZ의 영향을 받아 선언 전에 호출 불가
✅ 예제 코드
sayHello(); // "Hello, world!" (정상 실행)
function sayHello() {
console.log("Hello, world!");
}
// 함수 표현식 (ReferenceError 발생)
greet(); // ReferenceError
const greet = function() {
console.log("Hi!");
};
// 클래스 선언 (ReferenceError 발생)
console.log(person); // ReferenceError
class Person {}
4. Temporal Dead Zone(TDZ)란?
TDZ(일시적 사각지대, Temporal Dead Zone)는 let과 const로 선언된 변수가 초기화되기 전까지 접근할 수 없는 상태를 의미한다.
✅ 예제 코드
console.log(age); // ReferenceError (TDZ에 있음)
let age = 25;
📌 TDZ 특징:
- let, const에서만 발생 (var에서는 발생하지 않음)
- 변수가 선언되었지만 초기화되지 않으면 TDZ 상태에 있음
- TDZ에서는 변수에 접근할 경우 ReferenceError 발생
5. var을 지양하는 이유
var을 사용하면 Hoisting 시 undefined로 초기화되므로, 의도치 않은 버그 발생 가능성이 높음
따라서 의도적인 Hoisting 사용이 아니라면 let, const, 함수 표현식을 사용하는 것이 권장됨.
✅ 문제 발생 예시 (var의 의도치 않은 Hoisting)
console.log(score); // undefined
var score = 100;
위 코드에서는 score가 선언되기 전에 접근해도 undefined가 출력됨.
반면 let이나 const를 사용하면 TDZ로 인해 ReferenceError가 발생하여 코드 오류를 바로 확인할 수 있다.
📌 최종 정리
- Hoisting은 변수 및 함수 선언을 코드의 최상단으로 끌어 올리는 과정
- var은 undefined로 초기화되지만, let과 const는 TDZ로 인해 ReferenceError 발생
- 함수 선언식은 Hoisting되어 선언 전에 호출 가능하지만, 함수 표현식과 클래스 선언은 불가능
- 의도하지 않은 버그를 방지하기 위해 var 사용을 지양하고 let, const를 사용하는 것이 좋음
추가질문 예시
1. var, let, const의 Hoisting 방식은 각각 어떻게 다른가요?
선언 방식 | Hoisting 여부 | 초기화 여부 | TDZ (Temporal Dead Zone) |
var | O (호이스팅됨) | undefined로 초기화됨 | X (존재하지 않음) |
let | O (호이스팅됨) | 초기화되지 않음 (사용 시 ReferenceError) | O |
const | O (호이스팅됨) | 초기화되지 않음 (사용 시 ReferenceError) | O |
예제 코드:
console.log(a); // undefined
var a = 10;
console.log(b); // ReferenceError
let b = 20;
console.log(c); // ReferenceError
const c = 30;
정리:
- var은 undefined로 초기화되기 때문에 사용 가능.
- let과 const는 일시적 사각지대(TDZ)에 의해 선언 전에 접근 불가.
2. 함수 선언식(Function Declaration)과 함수 표현식(Function Expression)에서 Hoisting 차이는?
여부 선언 전 호출 가능 여부
구분 | Hoisting | 여부 선언 전 호출 가능 여부 |
함수 선언식 (function foo() {}) | O | O (선언 전에 호출 가능) |
함수 표현식 (const foo = function() {}) | X | X (선언 전에 호출 불가능) |
예제:
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
greet(); // ReferenceError
const greet = function() {
console.log("Hi!");
};
정리:
- function 선언식은 Hoisting이 적용되므로 선언 전에도 호출 가능
- const, let로 선언한 함수 표현식은 Hoisting되지 않음
3. TDZ(Temporal Dead Zone)이란 무엇인가요?
TDZ(일시적 사각지대, Temporal Dead Zone)란 let과 const로 선언된 변수가 초기화되기 전까지 접근할 수 없는 영역을 의미함.
예제 코드:
console.log(x); // ReferenceError (TDZ 영역)
let x = 10;
위 코드는 실행 시 에러가 발생함.
이는 let x가 Hoisting되었지만 초기화되지 않았기 때문임.
TDZ 특징:
- let과 const에서만 발생
- 변수가 선언되었지만 초기화되기 전까지는 접근 불가
- var에는 적용되지 않음 (undefined로 초기화됨)