다른 함수가 실행을 끝낸 뒤 실행되는 함수, 즉 코드를 통해 명시적으로 호출되는 함수가 아닌, 함수를 등록해놓은 후 어떠한 이벤트가 발생했거나 특정 시점에 도달했을 떄 시스템에서 호출하는 함수를 뜻합니다
기본적으로 Javascript는 동기적 프로그래밍 언어이다. 하지만 Callback함수를 이용해 비동기적 프로그래밍을 할 수 있습니다
또한 javascript는 싱글스레드를 사용하는데, 블로킹을 방지해줍니다. 따라서 싱글스레드가 논블로킹으로 동작하게 합니다.
블로킹 : 하나의 요청에 대한 응답이 와야만 다음 작업을 시작하는 방식
논블로킹 : 하나의 작업이 진행되는 동안 시간이 오래 걸리는 작업은 따로 마련한 공간에 던져 실행하는 방식
Promise 객체는 자바스크립트에서 비동기 처리에서 사용되는 객체입니다. 주로 서버에서 받아온 데이터를 화면에 표시하기 위해서 사용하며 데이터를 받아오기도 전에 데이터를 화면에 표시하려고 하면 오류가 발생하거나 빈 화면이 뜨게 되는데, 이러한 문제를 해결하기 위한 방법 중 하나입니다.
프로미스에는 세 가지 상태가 있습니다. 여기서 상태란 처리 과정을 의미합니다.
- Pending(대기): 비동기 처리 로직이 아직 완료되지 않은 상태
- Fulfilled(이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해 준 상태
- Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태
콜백 지옥과 같은 현상을 막고자 나온 것이 바로 Promise입니다. Promise가 콜백을 대체하는것은 아니지만 콜백을 예측가능한 패턴으로 사용할 수 있게 하며 Promise없이 콜백만 사용했을 때 예상치 못한 동작을 막아주거나 힘든 버그를 상당 수 해결해 줄 수 있습니다.
const onClickPromise = () => {
axios
.get("http://numbersapi.com/random?min=1&max=200")
.then((res) => {
const num = res.data.split(" ")[0];
return axios.get(`https://koreanjson.com/posts/${num}`);
})
.then((res) => {
const userId = res.data.UserId;
// prettier-ignore
return axios.get(`https://koreanjson.com/posts?userId=${userId}`)
})
.then((res) => {
console.log(res.data);
})
.catch(
// reject가 호출되면 catch가 실행
)
.finally(
// 콜백 작업을 마치고 무조건 실행되는 finally(생략가능)
};
위 코드 처럼 callback에 비해 코드가 비교적 간단해 지고, 콜백 지옥과 같은 현상도 일어나지 않습니다.
promise를 사용할 경우 각 요청들이 체인처럼 연결되는데, 이러한 것을 프로미스 체인 또는 프로미스 체이닝이라고 부릅니다.
const onClickPromise = () => {
const result = axios
.get("http://numbersapi.com/random?min=1&max=200")
.then((res) => {
const num = res.data.split(" ")[0];
return axios.get(`https://koreanjson.com/posts/${num}`);
})
.then((res) => {
const userId = res.data.UserId;
// prettier-ignore
return axios.get(`https://koreanjson.com/posts?userId=${userId}`)
})
.then((res) => {
console.log(res.data);
});
console.log(result)
};
위의 코드를 실행시키면 Promise의 형태로 들어오는 것을 확인할 수 있습니다.
const onClickPromise = () => {
console.log("여기는 1번입니다~");
axios
.get("http://numbersapi.com/random?min=1&max=200")
.then((res) => {
console.log("여기는 2번입니다~");
const num = res.data.split(" ")[0];
return axios.get(`https://koreanjson.com/posts/${num}`);
})
.then((res) => {
console.log("여기는 3번입니다~");
const userId = res.data.UserId;
// prettier-ignore
return axios.get(`https://koreanjson.com/posts?userId=${userId}`)
})
.then((res) => {
console.log("여기는 4번입니다~");
console.log(res.data);
});
console.log("여기는 5번입니다~");
};
위와 같은 코드에서 console을 보면 1 > 5 > 2 > 3 > 4 순서로 출력됩니다. 이것은 axios를 이용한 비동기 작업이 TaskQueue 안에 들어가, 순서가 뒤로 밀리기 때문입니다.
이러한 문제점들을 async, await를 통해 해결이 가능합니다.
async & await는 비동기식 코드를 동기식으로 표현하여 간단하게 나타내줍니다. 또한 promise의 직관적이지 못한 점 등 단점을 해결해주었습니다.
일단 코드부터 보자면 아래와 같습니다.
const onClickAsyncAwait = async () => {
console.log("여기는 1번입니다~");
// prettier-ignore
const res1 = await axios.get("http://numbersapi.com/random?min=1&max=200");
const num = res1.data.split(" ")[0];
console.log("여기는 2번입니다~");
const res2 = await axios.get(`https://koreanjson.com/posts/${num}`);
const userId = res2.data.UserId;
console.log("여기는 3번입니다~");
// prettier-ignore
const res3 = await axios.get(`https://koreanjson.com/posts?userId=${userId}`)
console.log(res3.data);
console.log("여기는 4번입니다~");
};
console에 출력되는 것도 1 > 2 > 3 > 4 로 출력이 되며, res1 등 변수에 값을 할당할 수도 있습니다.
async function 함수명(){
await 비동기_처리_메소드_이름()
}
예외처리를 해줄 때는 try, catch를 사용하면 됩니다
async function loadData(){ try{ const result = await Data() console.log(result) } catch(e){ console.log(e) } }