사진 자료 출처: https://learnjs.vlpt.us/async/
자바스크립트에서 함수를 비동기 처리 해주는 첫 번째 방법으로는 setTimeout()이 있다.
- setTimeout(실행하고자 하는 함수, 기다릴 시간 ms)
console.log(1); setTimeout(() => { console.log(2); }, 3000); console.log(3);
위 코드는 1, 3을 차례로 출력후, 3초 기다린 2가 출력된다.
비동기적인 함수를 실행 시, API요청 같은 실행 순서가 중요한 코드 같은 경우에 특별한 처리를 해주지 않으면 실행 순서가 꼬여 실행이 불가능 한 경우가 생긴다.
이 때 해주는 것이 callback으로, 다른 코드가 특정한 코드가 종료되기 전에 실행되지 않도록 해준다.
callback이 없을 때 밑 코드를 실행한다면, second의 내용이 먼저 출력되고 그 다음 first의 내용이 출력될 것이다.
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 5000 );
}function second(){
console.log(2);
}
first()
second()
그러나, setTimeout만으로는 무조건 second내용이 먼저 출력되고 first가 출력된다고 보기에는 어렵다.
따라서, 다른 함수를 callback인자로 받아 비동기 처리에서도 순서가 보장 될 수 있도록 하는 것이 바로 callback이다.
function first(callback){
// Simulate a code delay
setTimeout( function(){
console.log(1);
callback();
}, 5000 );
}function second(){
console.log(2);
}
first(second)
이 코드에서는 second 함수를 first의 callback인자로 받아, 둘은 서로 비동기 관계이나 first가 실행된 이후 second가 실행되도록 실행 순서를 보장하고 있다.
callback은 여러 함수의 실행 순서를 결정할 때는 과도하게 코드가 복잡해지는 문제가 생긴다.
function fun1(callback) {
setTimeout(() => {
console.log("1");
setTimeout(() => {
console.log("2");
setTimeout(() => {
console.log("3");
callback();
}, 1000);
}, 1000);
}, 1000);
}
function fun2() {
console.log("4");
}
fun1(fun2);
따라서 우리가 사용하는 것이 바로 promise, async-await이다.
promise의 상태에는 3가지가 있는데,
- 1. Pending : 대기, 비동기 로직이 아직 완료되지 않음.
- 2. Fulfill : 이행(resolve), 비동기 로직 처리되어 프로미스가 결과 값을 반환함
- 3. Rejected : 실패(rejected), 오류 발생
promise의 기본 형태는 다음과 같다.
function getData() {
return new Promise(function(resolve, reject) {
var data = 100;
resolve(data);
});
}
getData().then(function(resolvedData) {
console.log(resolvedData); // 100
});
promise에서 resolve인자를 호출하면, promise의 상태는 fulfill이 되고, 이때 then에서 처리 결과 값을 받을 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
reject(new Error("Request is failed"));
});
}
// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
console.log(err); // Error: Request is failed
});
promise에서 reject인자를 호출한 경우, promise의 상태는 rejected가 되고, catch를 통해 에러 값을 받을 수 있다.
promise는 여러 개의 프로미스를 연결하여 사용할 수 있다. then()메서드를 호출하면 새로운 프로미스 객체가 반환되고, 그 다음 then에서 프로미스 객체를 다시 받을 수도 있다.
function getData() {
return new Promise({
// ...
});
}
// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
.then(function(data) {
// ...
})
.then(function() {
// ...
})
.then(function() {
// ...
});
async, await는 가장 최근에 나온 문법으로, 가독성이 좋아 많이 사용되고 있다.
function logName() {
var user = fetchUser('domain.com/users/1');
if (user.id === 1) {
console.log(user.name);
}
}
domain.com에서 user 정보를 받아오는 위 예제의 경우, 이 것만으로는 user데이터를 받고, user.id를 비교하는 순서를 보장 할 수 없으므로 함수를 비동기화 해주어야 한다. 이때 우리가 공부한 callback함수를 사용하면 아래와 같이 정리가 되어야 한다. user.id를 비교하는 구문을 일종의 함수로 하여 fetchUser의 인자로 넣어주었다.
function logName() {
var user = fetchUser('domain.com/users/1', function{
if (user.id === 1) {
console.log(user.name);
}
});
}
그러나 이를 위해서 우리는 fetchuser의 인자도 신경써주어야 하고, 코드의 가독성 또한 떨어진다. 이때 async&await를 쓰면 쉽게 코드를 변경할 수 있다.
async function logName() {
var user = await fetchUser('domain.com/users/1');
if (user.id === 1) {
console.log(user.name);
}
}