비동기 처리
Javascript의 비동기 처리
- 자바스크립트는 특정 코드를 비동기 처리한다.
- 어떤 코드의 연산이 끝날 때까지 기다리지 않고,
- 다음 코드를 먼저 실행해버린다.
- 파일 처리나 데이터 페칭 등이 있다.
- 브라우저 위에서 돌아간다는 자바스크립트의 특징 때문에 오래 걸리는 작업을 기다려줄 수 없다.
- 서버의 요청을 받아 화면에 띄워주는 역할을 하기 때문에
- 하나하나 다 기다려줄 수는 없다.
- 받아오면 그때 띄우고를 반복해 빠르게 화면을 구성하는 것이다.
1
2
3
4
5
6
7
8
9
10
11
sendMessage=()=>{
console.log('팀장님 인생');
setTimeout(()=>{
console.log('최고라던 그 가게');
},3000);
console.log('망했어요.');
};
sendMessage();
- 자바스크립트가 비동기라는걸 모르는 나같은 사람들은
- 팀장님 인생
- (약 3초 뒤)
- 최고라던 그 가게
- 망했어요.
- 이 순서를 생각할 것이다.
- 그러나 setTimeout이 3초를 기다리는 동안 훅 지나가 뒤에 코드를 먼저 실행한다.
- 팀장님 인생
- 망했어요.
- (약 3초 뒤)
- 최고라던 그 가게
콜백 함수
- 위의 비동기를 잡을 수 있는 방법으로 콜백 함수가 있다.
- 콜백 함수란,
- 특정 메서드가 끝나면 실행시켜주세요 하는 함수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
sendMessage=(end)=>{
console.log('팀장님 인생');
setTimeout(()=>{
console.log('최고라던 그 가게');
end();
},3000);
};
sendMessage(()=>{
console.log('망했어요.')
});
- sendMessage를 호출할 때 마지막 메시지를 띄우는 콜백 함수를 넘겨준다.
- sendMessage 내부에서 콜백 함수를 호출해서 예상되는 결과를 얻을 수 있었다.
- 팀장님 인생
- (약 3초 뒤)
- 최고라던 그 가게
- 망했어요.
- 그러나 프로그램을 짜다보면 코드는 점점 더 복잡해질 수 밖에 없고,
- 비동기 처리가 겹겹으로 필요한 경우가 생긴다.
- 그때마다 콜백 함수를 처리해주면 indent가 자꾸 늘어나고
- 코드가 복잡해지게 된다. 이것을 콜백 지옥이라고 하더라.
Promise
- Promise 역시 비동기 처리를 위한 객체이다.
- Promise에는 세 가지 상태가 있다.
- Pending
- 비동기 로직 처리가 끝나길 기다리는 상태
- Fulfilled
- 비동기 로직 처리가 끝나고 결과 값을 반환한 상태
- Rejected
- 비동기 로직 처리 중에 오류가 발생한 상태
- Pending
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sendMessage=(end)=>{
console.log('팀장님 인생');
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('최고라던 그 가게');
resolve(); // 얘가 실행되면 아래의 then()이 호출됨.
},3000);
});
};
sendMessage()
.then(res=>{ // res는 Promise의 결과 값.
console.log("망했어요.");
});
- 생성이 완료된 Promise는 처음엔 Pending 상태이다.
- resolve()가 호출되는 시점에 Fulfilled가 된다.
- reject()가 호출되는 시점에 Rejected가 된다.
- 이 경우는 then()이 아닌 catch()로 받을 수 있다.
async, await
- 얘네 역시 비동기 처리를 위한 문법이다.
- 프라미스를 좀 더 편하게 사용할 수 있다.
- async는 함수 앞에 위치한다.
- async가 붙은 함수는 항상 이행된(fulfilled) Promise 객체를 리턴한다.
- 만약 async가 아닌 리턴 값을 가진다고 해도, fulfilled Promise로 감싸서 리턴한다.
- await은 async가 붙은 함수 내에서만 사용이 가능하다.
- await 키워드는 비동기 처리가 끝날 때 까지 기다린다.
- await이 붙은 프라미스 처리가 끝나면 그 뒤의 코드가 동작한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
async function sendMessage() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('최고라던 그 가게');
}, 3000);
});
console.log('팀장님 인생');
console.log(await promise);
console.log('망했어요.');
}
- 내가 원하던 결과가 나온다.
- 팀장님 인생
- (약 3초 대기)
- 최고라던 그 가게
- 망했어요.
- await 키워드를 만나면 처리가 끝날 때까지 기다리기 때문에 원하던 결과를 얻을 수 있었다.
- 이행된 프라미스를 받기 때문에 깔끔한 코드를 작성할 수 있다.
에러 핸들링
- await가 붙은 프라미스는 에러가 발생하면 throw한다.
- 예를 들어,
- await Promise.reject(new Error(‘error’)); 는
- throw new Error(‘error’) 와 같다.
- 이 경우 역시 try/catch 문으로 에러를 잡아줘야 한다.
- 만약 에러를 잡아주지 않으면 rejected Promise를 리턴한다.
- 이런 경우 프라미스 에러가 발생한다.
- .catch() 메서드로 에러를 잡아줄 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// try/catch로 잡는 방법
async function error1() {
try {
await Promise.reject(new Error('error111'));
} catch(e) {
console.log(e.message);
}
}
error1(); // error111
async function error2() {
await Promise.reject(new Error('error222'));
}
// 에러를 잡지 않은 경우.
error2(); // Uncaught Error
// catch()로 에러를 잡은 경우.
error2()
.catch(err => console.log(err.message)); // error222
This post is licensed under CC BY 4.0 by the author.