학습 목표
- 어떤 경우에 중첩된 콜백(callback)이 발생하는지 이해할 수 있다.
- 중첩된 콜백(callback)의 단점, Promise의 장점을 이해할 수 있다.
- async/await 키워드에 대해 이해하고, 작동 원리를 이해할 수 있다.
동기(synchronous)
비동기(asynchronous)
💡) 동기, 비동기 쉽게 이해하기
친구에게 메시지를 보내고 응답을 기다리는 상황을 생각해보자.
동기적으로 처리한다면, 메시지를 보낸 후에 친구가 응답할 때까지 기다려야한다.
하지만 비동기적으로 처리한다면, 메시지를 보낸 후에 다른 일을 할 수 있고, 친구가 응답하면 그 때 처리할 수 있다.
💡) JavaScript에서의 비동기 이해하기
웹 페이지에서 이미지를 로드하는 경우
동기적인 방식으로 이미지를 로드한다면, 이미지를 다운로드할 때까지 다른 작업은 중단되어 사용자는 그동안 아무것도 할 수 없게 된다.
하지만 비동기적인 방식으로 이미지를 로드한다면, 이미지를 다운로드 하는 동안에도 다른 작업을 처리할 수 있고, 사용자는 웹 페이지를 계속 탐색하거나 다른 동작을 할 수 있다.
* 스레드(thread)
- 프로그램 내에서 실행되는 독립적인 작업의 흐름
* 멀티 스레드
- 스레드를 동시에 실행하여 여러 작업을 동시에 처리
- 하나의 스레드가 사용자 인터페이스를 업데이트하고, 다른 스레드가 파일을 읽어오는 작업 처리와 같은 걸 할 수 있음
* 싱글 스레드
- 한 번에 하나의 작업만을 처리할 수 있음
💡) API가 뭘까?
API(Application Programming Interface)는 프로그램과 다른 프로그램 또는 서비스 간에 상호작용을 하기 위한 규칙과 도구의 집합이다.
프로그램이 다른 프로그램과 정보를 주고 받을 수 있도록 하는 역할을 한다.
예를 들어, 날씨 정보를 알고 싶다면, 날씨 서비스의 API를 사용해서 프로그램이 날씨 정보를 얻을 수 있게 한다.
프로그램들이 서로 소통하고 상호작용하는 방법을 정의하는 일종의 계약이라고 할 수 있고, 어떤 종류의 데이터를 요청할 수 있는지, 어떻게 요청해야 하는지, 어떤 종류의 응답을 받을 수 있는지에 대한 규칙을 제공한다.
- 참고 : MDN API
setTimeout(callback, millisecond)
setTimeout(function () {
console.log('1초 후 실행');
}, 1000);
// 123
clearTimeout(timerId)
setTimeout
타이머를 종료const timer = setTimeout(function () {
console.log('10초 후 실행');
}, 10000);
clearTimeout(timer);
// setTimeout이 종료됨.
setInterval(callback, millisecond)
setInterval(function () {
console.log('1초마다 실행');
}, 1000);
// 345
```
clearInterval(timerId)
setInterval
타이머를 종료const timer = setInterval(function () {
console.log('1초마다 실행');
}, 1000);
clearInterval(timer);
// setInterval이 종료됨.
콜백함수(callback)
일반적으로 콜백함수는 비동기 함수의 마지막 인자로 전달되며, 비동기 작업이 완료되면 콜백 함수가 호출됨 → 비동기 작업의 결과를 받아서 처리하거나 추가 동작 수행
예시
function delayedHello(callback) {
setTimeout(function() {
console.log("Hello, World!");
callback();
}, 1000);
}
// delayedHello 함수는 콜백 함수를 인자로 받아서, 1초 후에 "Hello, World!"를 출력한 뒤에 콜백 함수를 호출
function afterDelay() {
console.log("After delay");
}
// afterDelay 함수는 콜백 함수로 전달되어서 "After delay"를 출력
delayedHello(afterDelay);
new Promise
Promise
는 class이기 때문에 new
키워드를 통해 promise
객체 생성resolve
, reject
함수를 인수로 전달 받음Promise
객체가 생성되면 executor
는 자동으로 실행되고 작성한 코드들이 작동
resolve
함수 호출reject
함수 호출Promise
객체는 state
, result
내부 프로퍼티를 가짐
.then
, .catch
, .finally
메서드를 사용해서 접근State
pending
(대기)fulfilled
(이행)으로 변경rejected
(거부)Result
undefined
resolve(value)
가 호출되면 value
로 변경reject(error)
호출되면 error
로 변경Then
executor
에 작성한 코드가 정상적으로 처리가 됐으면, resolve
함수를 호출하고 .then
메서드로 접근할 수 있음.then
안에서 리턴한 값이 Promise
면 내부 프로퍼티의 result
를 다음 .then
의 콜백함수의 인자로 받아옴Catch
executor
에 작성한 코드들이 에러가 발생했을 경우 reject
함수를 호출하여 .catch
메서드로 접근 가능Finally
executor
에 작성한 코드들의 정상처리 여부와 상관 없이 .finally
메서드로 접근 가능예시
// "요청 시작"을 출력한 후 2초를 기다린 뒤 데이터를 받아온 메시지를 출력하고 "요청 완료"를 출력, 만약 데이터를 받아오지 못했다면 오류 메시지가 출력하는 예시
function fetchData() {
return new Promise(function(resolve, reject) {
// 비동기 작업 시뮬레이션
setTimeout(function() {
const data = "데이터가 도착했습니다!";
// 데이터를 성공적으로 받아온 경우
if (data) {
resolve(data);
} else {
reject("데이터를 받아오지 못했습니다.");
}
}, 2000);
});
}
// fetchData 함수를 호출하여 데이터를 가져오는 Promise를 생성하고
// fetchData 함수는 2초 후에 데이터를 성공적으로 받아온 경우 resolve를 호출하고, 그렇지 않은 경우 reject를 호출
console.log("요청 시작");
fetchData()
// then을 사용하여 Promise가 성공적으로 해결된 경우 데이터를 출력
.then(function(response) {
console.log("데이터 받음:", response);
})
// catch를 사용하여 Promise가 실패한 경우 오류 메시지를 출력
.catch(function(error) {
console.log("오류 발생:", error);
})
// finally는 Promise가 해결되었든 실패했든 상관없이 항상 실행
.finally(function() {
console.log("요청 완료");
});
.then
, .catch
, .finally
의 메서드들은 Promise
를 리턴하기 때문에 Promise chaining이 가능.then
을 통해 연결할 수 있고, 에러가 발생할 경우 .catch
로 처리함let promise = new Promise(function(resolve, reject) {
resolve('성공');
...
});
promise
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.then((value) => {
console.log(value);
return '성공';
})
.catch((error) => {
console.log(error);
return '실패';
})
.finally(() => {
console.log('성공이든 실패든 작동!');
});
Promise
에서 executor
내 작성했던 코드들이 정상적으로 처리가 되었다면 결과를 배열에 저장해 새로운 Promise
를 반환 Promise.all([
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러1'))), 1000),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러2'))), 2000),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('에러3'))), 3000),
])
.then((value) => console.log(value))
.catch((err) => console.log(err));
// Error: 에러1
// 함수 선언식
async function funcDeclarations() {
await 작성하고자 하는 코드
...
}
// 함수 표현식
const funcExpression = async function () {
await 작성하고자 하는 코드
...
}
// 화살표 함수
const ArrowFunc = async () => {
await 작성하고자 하는 코드