728x90
반응형
SMALL
Promise, async/await
질문 1. 동기와 비동기는 무엇인가요?
- 동기 : 현재 실행 중인 코드가 완료된 후에 다음 코드를 실행하는 방식 입니다.
- CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드
- 비동기: 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어갑니다.
- setTimeout, addEventListener, XMLHttpRequest 등
질문 2. Promise은 무엇이고, Promise의 상태에 대해서 설명해주세요
- ES6에서 비동기 처리를 위한 패턴으로 프로미스를 도입했고, Promise 객체는 비동기 작업을 완료(fulfilled) 또는 실패(rejected)와 결과 값을 나타내는 객체 입니다.
Promise는 세 가지 상태를 가질 수 있습니다.
- Pending (대기): 초기 상태, 비동기 작업이 아직 완료되지 않은 상태.
- Fulfilled (이행): 비동기 작업이 성공적으로 완료된 상태. resolve 함수를 호출하여 이 상태로 변경됩니다.
- Rejected (실패): 비동기 작업이 실패한 상태. reject 함수를 호출하여 이 상태로 변경됩니다.
Promise 상태 변경
- Pending → Fulfilled: 비동기 작업이 성공하면 resolve(value)가 호출되어 Promise는 fulfilled 상태가 됩니다. value는 성공 결과입니다.
- Pending → Rejected: 비동기 작업이 실패하면 reject(reason)가 호출되어 Promise는 rejected 상태가 됩니다. reason은 실패 이유입니다.
// Promise 생성
let promise = new Promise((resolve, reject) => {
let success = true; // 비동기 작업의 성공 여부를 나타내는 변수 (예시)
// 비동기 작업 (예: 타임아웃)
setTimeout(() => {
if (success) {
resolve("작업이 성공했습니다!"); // 작업 성공 시 resolve 호출
} else {
reject("작업이 실패했습니다."); // 작업 실패 시 reject 호출
}
}, 1000);
});
// Promise 사용
promise.then((result) => {
console.log(result); // "작업이 성공했습니다!" 출력
}).catch((error) => {
console.error(error); // "작업이 실패했습니다." 출력
});
// 설명: promise가 생성된 후 1초 뒤에 resolve 또는 reject를 호출하여 상태를 변경한다.
// then 메서드는 Promise가 fulfilled 상태일 때 실행되고, catch 메서드는 Promise가 rejected 상태일 때 실행
질문 3. Promise.all과 Promise.allSettled, Promise.race에 대해 설명해주세요
Promise.all:
- Promise.all 메서드는 여러 개의 비동기 처리를 한꺼번에 병렬 처리할 때 사용한다.
- 모든 프로미스가 성공(fulfilled)하면 그 결과를 배열로 반환한다. 하지만, 하나의 프로미스라도 실패(rejected)하면 즉시 실패하고, 나머지 프로미스의 결과는 무시된다.
# 예시 1
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 예상 출력: [3, 42, "foo"]
})
.catch((error) => {
console.error(error);
});
// 위 예시에서 promise1, promise2, promise3 모두 성공(fulfilled)하면 Promise.all은 [3, 42, "foo"]를 출력합니다.
// 만약 하나라도 실패(rejected)하면 catch 블록이 실행됩니다.
# 예시 2.
const promise1 = Promise.resolve('Success 1');
const promise2 = Promise.reject('Failure');
const promise3 = Promise.resolve('Success 3');
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 이 블록은 실행되지 않습니다.
})
.catch((error) => {
console.error(error); // 출력: Failure
});
Promise.allSettled:
- Promise.allSettled 메서드는 프로미스를 요소로 갖는 배열을 인수로 받아, 모든 프로미스가 완료(settled)될 때까지 기다린다. 프로미스가 성공(fulfilled)했는지 실패(rejected)했는지와 상관없이 결과를 배열로 반환한다.
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'error');
});
const promise3 = Promise.resolve('foo');
Promise.allSettled([promise1, promise2, promise3])
.then((results) => {
results.forEach((result) => console.log(result));
});
// promise1이 성공(fulfilled), promise2가 실패(rejected), promise3이 성공(fulfilled)하는데,
// Promise.allSettled는 각 프로미스의 결과를 배열로 반환합니다. 출력은 다음과 같습니다:
// 결괏값
// { status: 'fulfilled', value: 3 }
// { status: 'rejected', reason: 'error' }
// { status: 'fulfilled', value: 'foo' }
Promise.race:
- Promise.race 메서드는 프로미스를 요소로 갖는 배열의 이터러블을 인수로 전달받는다. 전달된 프로미스들 중 가장 먼저 완료된(fulfilled 또는 rejected) 프로미스의 결과만을 반환한다.
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'First');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'Second');
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(reject, 200, 'Third');
});
Promise.race([promise1, promise2, promise3])
.then((value) => {
console.log(value); // 예상 출력: 'Second'
})
.catch((error) => {
console.error(error);
});
// promise1은 500ms 후에 성공(fulfilled)하며, 값으로 'First'를 반환합니다.
// promise2는 100ms 후에 성공(fulfilled)하며, 값으로 'Second'를 반환합니다.
// promise3는 200ms 후에 실패(rejected)하며, 이유로 'Third'를 반환합니다.
// 만약 promise2가 없고 promise3가 가장 빨리 완료되었다면,
// Promise.race는 promise3의 실패 이유인 'Third'를 반환하게 됩니다.
질문 5. 자바스크립트에서 Callback을 사용하는 상황 세 가지를 설명해주세요.
# 1. 이벤트 리스너로 사용
## addEventListener는 특정 이벤트가 발생했을 때 콜백함수를 실행하는 메서드이다.
let button = document.getElementById("button"); // 버튼 요소를 선택
// 버튼에 클릭 이벤트 리스너를 추가
button.addEventListener("click", function () { // 콜백 함수
console.log("Button clicked!");
});
# 2. 고차함수에 사용
## 자바스크립트에서 for문 보다 더 자주 사용되는 반복문이 forEach 메서드일 것이다.
forEach 메서드의 입력값으로 콜백 함수를 전달하는 형태임을 볼 수 있다.
// 예시 : 배열의 각 요소를 두 배로 곱해서 새로운 배열을 생성하는 콜백 함수
let numbers = [1, 2, 3, 4, 5]; // 배열 선언
let doubled = []; // 빈 배열 선언
// numbers 배열의 각 요소에 대해 콜백 함수 실행
numbers.forEach(function (num) {
doubled.push(num * 2); // 콜백 함수로 각 요소를 두 배로 곱해서 doubled 배열에 추가
});
console.log(doubled); // [2, 4, 6, 8, 10]
# 3. 타이머 실행 함수로 사용
setTimeout이나 setInterval과 같은 타이머 함수에서
일정 시간마다 스크립트를 실행하는 용도로서 콜백 함수를 이용한다.
// 3000 밀리초(3초) 후에 콜백 함수 실행
setTimeout(function () {
console.log("Time is up!"); // 콜백 함수로 콘솔에 메시지 출력
}, 3000);
# 4. 애니메이션 완료
## jQuery에서 제공하는 애니메이션 메서드들은 애니메이션이 끝난 후에 실행할 콜백 함수를 인자로 받는다.
// jQuery의 slideUp 메서드를 사용하여 #box 요소를 숨기고 콜백 함수로 콘솔에 메시지 출력
$("#box").slideUp(1000, function () {
console.log("Animation completed!"); // 콜백 함수로 콘솔에 메시지 출력
});
# 5. Ajax 결과값을 받을 때 사용
## 서버와 데이터를 주고받을 때 사용하는 fetch 메서드의 서버 요청의 결과값을 처리하기 위해 콜백 함수가 사용된다.
// fetch 메서드를 사용하여 서버로부터 JSON 데이터를 받아오고 콜백 함수로 화면에 출력
fetch("<https://jsonplaceholder.typicode.com/users>")
.then(function (response) {
// fetch 메서드가 성공하면 콜백 함수로 response 인자를 받음
return response.json(); // response 객체의 json 메서드를 호출하여 JSON 데이터를 반환
})
.then(function (data) {
// json 메서드가 성공하면 콜백 함수로 data 인자를 받음
console.log(data);
})
질문 6. callback Hell과 Promise와 차이점에 설명해주세요.
- 콜백 헬은 코드의 가독성이 떨어지는 반면에, 프로미스는 체이닝을 활용하여 코드의 가독성이 콜백함수에 비해 상대적으로 쉽다.
# callback hell
function firstFunction(callback) {
setTimeout(() => {
console.log('First function');
callback();
}, 1000);
}
function secondFunction(callback) {
setTimeout(() => {
console.log('Second function');
callback();
}, 1000);
}
function thirdFunction(callback) {
setTimeout(() => {
console.log('Third function');
callback();
}, 1000);
}
firstFunction(() => {
secondFunction(() => {
thirdFunction(() => {
console.log('All functions completed');
});
});
});
# promise
function firstFunction() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('First function');
resolve();
}, 1000);
});
}
function secondFunction() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Second function');
resolve();
}, 1000);
});
}
function thirdFunction() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Third function');
resolve();
}, 1000);
});
}
firstFunction()
.then(() => secondFunction())
.then(() => thirdFunction())
.then(() => {
console.log('All functions completed');
})
.catch((error) => {
console.error(error);
});
- 이와 같은 코드에서 각 비동기 함수는 프로미스를 반환하며, then 메서드를 통해 순차적으로 실행된다. 이렇게 체이닝을 통해 코드의 가독성이 높아지고, 비동기 작업의 흐름을 쉽게 파악할 수 있다.
질문 7. async/await에 개념과 사용법에 대해 설명해주세요.
개념:
- async/await은 ES8에서 제너레이터보다 간단하고 가독성 좋게 비동기 처리를 동기 처리처럼 동작하도록 구현할 수 있게 도입되었다. async/await을 사용하면 프로미스의 then/catch/finally 후속 처리 메서드 없이 마치 동기 처리처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다.
const handleDelete = async (id) => {
await deleteDoc(doc(db, "todos", id));
};
- handleDelete 함수에서는 Firestore 데이터베이스에 대한 비동기 작업을 수행하고 있습니다. 이 함수는 async 키워드로 선언되었으며, await 키워드를 사용하여 비동기 작업이 완료될 때까지 기다립니다.
- handleDelete함수에 async await 뺸다면 async/await를 사용하지 않는 handleDelete 함수가 Firestore 데이터베이스에서 문서를 삭제하는 비동기 작업을 시작하지만, 그 작업이 완료되기를 기다리지 않고 바로 함수(다음 코드를 실행)를 종료합니다. 이후에 비동기 작업이 완료되면 그 결과는 처리되지 않고 무시됩니다.
사용법:
- async 와 await 는 function 키워드 앞에 async 만 붙여주면 되고, 비동기로 처리되는 부분 앞에 await 만 붙여주면 된다.
# 콜백 함수에서 프로미스를 then으로 처리하는 방법
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`Waited for ${ms} milliseconds`);
}, ms);
});
}
delay(2000).then(message => {
console.log(message); // 2초 후에 'Waited for 2000 milliseconds' 출력
}).catch(error => {
console.error(error);
});
// delay 함수는 ms 밀리초 후에 resolve를 호출하는 프로미스를 반환합니다.
// setTimeout을 이용해 ms 밀리초 후에 resolve 함수를 호출하여 프로미스가 완료되도록 합니다.
// delay(2000)을 호출하여 2초 후에 프로미스가 해결되도록 하고, then 메서드를 사용하여 해결된 후의 작업을 처리합니다.
# async와 await을 이용하는 방법
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`Waited for ${ms} milliseconds`);
}, ms);
});
}
async function asyncDelayExample() {
try {
const message = await delay(2000);
console.log(message); // 2초 후에 'Waited for 2000 milliseconds' 출력
} catch (error) {
console.error(error);
}
}
asyncDelayExample();
결론적으로 1)콜백 헬의 단점으로 → 2) Promise는 콜백 헬을 해결하고자 하였고, then() 메서드 체이닝을 통해 비동기 코드를 좀 더 명확하게 작성할 수 있게 되었다. 하지만 then() 메서드 체이닝이 복잡성을 줄이긴 했지만, 여전히 비동기 코드를 작성하는 것에 있어서 가독성과 이해하기 쉬운 코드를 만드는 데 어려움이 있었다. → 3)그래서 나온 것이 async/await다.
728x90
반응형
LIST
'FE' 카테고리의 다른 글
[스터디] 8주차 자바스크립 (모던 자바스크립트 deep dive) (2) | 2025.01.28 |
---|---|
[스터디] 7주차 자바스크립트 (모던 자바스크립트 deep dive) (0) | 2025.01.28 |
[스터디] 6주차 자바스크립 (모던 자바스크립트 deep dive) (0) | 2025.01.28 |
[스터디] 5주차 자바스크립 (모던 자바스크립트 deep dive) (0) | 2025.01.28 |
[스터디] 4주차 자바스크립 (모던 자바스크립트 deep dive) (0) | 2025.01.28 |