JS 비동기 함수 정리
자바스크립트 비동기 함수 관련 정리
세줄 요약.
async function
,await
,Promise
,.then()
얘네들은 비동기 처리를 위한 키워드임.async function
,.then()
은 리턴값을Promise
로 포장해서 준다.- 포장된 값은
await
로 받을 수 있다.
예제
HTTP request
HTTP 요청하고 응답을 받기까지 시간이 걸리고 그 동안 다른 JS 코드가 돌아갈 수 있다.
1
2
3
4
5
let xhr = new XMLHttpRequest();
xhr.open("get", "url");
xhr.send();
let result = xhr.response;
console.log(result);
위 코드를 실행하면 undefined
가 나옵니다. 하지만 디버그 모드에서 한줄씩 천천히 실행하면 result 값이 나오게 됩니다. response 를 받아오는데 시간이 걸려서, JS 가 먼저 실행되는 경우 result 에 아무것도 할당되지 않기 때문입니다. 그래서 보통 아래처럼 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
let xhr = new XMLHttpRequest();
xhr.open("get", "url");
xhr.onload = function() {
if(xhr.readyState === 4 && xhr.ststus === 200){
let result = xhr.response;
console.log(result);
} else {
console.log("failed to request");
}
}
xhr.send();
이러면 요청 응답이 끝난 후 .onload()
가 실행되면서 비동기 처리를 할 수 있습니다. 하지만 코드가 위부터 아래로 순차적으로 실행되지 않고 나중에 실행될 코드를 중간에 작성해야 해서 맘에 안듭니다.
요청 및 응답을 받는 과정을 묶어서 async function
으로 만들어봅니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
async function sendGetRequest(url){
let xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.onload = function() {
if(xhr.readyState === 4 && xhr.ststus === 200){
return xhr.response;
} else {
throw "error";
}
}
}
let result = await sendGetRequest("url");
console.log(result);
async function
은 리턴값을 Promise
로 감싸주기 때문에, await
로 (기다리고) 포장을 풀면 됩니다. 아래 코드와 동등한데…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function sendGetRequest(url){
return new Promise(
(resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.onload = function() {
if(xhr.readyState === 4 && xhr.ststus === 200){
resolve(xhr.response);
} else {
reject("error");
}
}
}
);
}
let result = await sendGetRequest("url");
console.log(result);
Promise
를 리턴하는 함수는 .then()
으로 다른 작업을 순서대로 실행하게 만들 수 있다. 이 때 .then()
내부에선 Promise
포장이 벗겨진 것 처럼 사용할 수 있지만, 리턴값은 또 다른 Promise
를 줍니다.
1
2
3
4
sendGetRequest().then(
(resolve)=> {...},
(reject) => {...}
);
.then()
도 Promise
를 리턴하기 때문에, .then(...).then.(...)...
처럼 계속 이어갈 수 있어요.
1
2
3
4
sendGetRequest()
.then( handleResolve1, handleError )
.then( handleResolve2, handleError )
...
fetch()
Promise
를 쓰지 않고 XMLHttpRequest
의 .onload()
를 써도 되지만, Promise
를 사용하여 좀 더 보기 좋게 코드를 짤 수 있습니다. 서버의 설정 파일 리소스를 읽을 때 이런 식으로 짤 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
async function loadConfig(fileName) {
return (await fetch(fileName)).json();
}
loadConfig("myConfig.json").then(
(resolve) => {
let configInMemory = resolve;
}
).then(
(resolve) => {
init();
...
}
);
XMLHttpRequest
의 .onload()
를 사용할 때와 달리 코드가 위에서 아래로 간단하게 읽힙니다.
마치며
저에겐 좀 생소한 문법이긴 한데, Promise
로 포장된다는 점만 잘 숙지하면 될 것 같습니다. 잘 이해하기 위해선 비동기 처리를 콜백으로 해결했을 때와 비교하면 되는데, 콜백 함수만 사용하면 실행 순서만큼 블록 레벨이 깊어지지만, Promise
를 쓰면 .then()
으로 연쇄 처리가 가능합니다.