function delay(sec, callback) {
setTimeout(() => {
callback(new Date().toISOString());
}, sec * 1000);
}
// 동기
delay(1, result => {
console.log(1, result);
});
delay(1, result => {
console.log(2, result);
});
delay(1, result => {
console.log(3, result);
});
// 출력
// (1초뒤 동시에 출력)
// 1
// 2
// 3
1초 뒤에 1, 2, 3이 동시에 출련된다.
자바스크립트는 기본적으로 동기적으로 동작한다. 콜백함수를 사용한다 해서 항상 비동기로 동작하는것이 아니다.
자바스크립트의 비동기를 제대로 이해하기 위해서는 이전에 작성한 자바스크립트의 비동기 동시성 프로그래밍 글을 참고하자.
비동기 프로그래밍은 메인의 작업 흐름에서 특정 작업을 분리해서 새로운 작업 흐름을 만들어 병렬적으로 처리하는 방식이다.
function delay(sec, callback) {
setTimeout(() => {
callback(new Date().toISOString());
}, sec * 1000);
}
delay(1, result => {
console.log(1, result);
delay(1, result => {
console.log(2, result);
delay(1, result => {
console.log(3, result);
});
});
});
// 출력
// (1초의 간격을 두고 출력)
// 1
// 2
// 3
1초 뒤 1부터 1초의 간격으로 출력이 된다.
콜백에 콜백으로 구현하는 콜백지옥이 구현되는 이유는
위 코드에서 1
이라는 분리된 작업 뒤에 2
와 3
이라는 작업 흐름을 이어주기 위해서는 콜백에 콜백을 넘겨주는 식으로 구현할 수 밖에 없었기 때문이다.
콜백지옥을 벗어나기 위해 등장한 문법이
Promise
와async/await
이다.
Promise
와async/await
는 필요한 상황에 따라 선택하여 사용하면 된다.
resolve
, reject
으로 값을 갖는 프로미스를 리턴한다.then
, catch
, finally
을 사용한다.function delayP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Date().toISOString());
}, sec * 1000);
});
}
delayP(1) //
.then(res => {
console.log(1, res);
return delayP(1);
})
.then(res => {
console.log(2, res);
return delayP(1);
})
.then(res => {
console.log(3, res);
return delayP(1);
})
.finally(() => console.log('끝'));
// 출력
// (1초의 간격을 두고 출력)
// 1
// 2
// 3
// 끌
1초 뒤 1부터 1초의 간격으로 출력이 된다.
콜백으로 구현한 비동기 방식보다 훨씬 직관적이다.
const getHen = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 1000);
});
};
const getEgg = hen => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${hen} => 🥚`), 1000);
});
};
const cook = egg => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
};
getHen()
.then(hen => getEgg(hen))
.then(egg => cook(egg))
.then(console.log)
.finally(() => console.log('끝'));
// 출력
// 🐓 => 🥚 => 🍳
// 끝
각각의 비동기 작업(promise
)를 then
으로 하나의 작업흐름으로 만들기 때문에 간결하고 사용하기 쉽다.
async
는 함수의 리턴을 프로미스로 바꿔준다.
async
는 함수의 리턴값은 프로미스의 resolve
와 동일하다.
async
함수의 리턴값이 then
의 인자로 절달된다.
await
은 async
함수 내의 프로미스의 결과를 기다리게 한다. (비동기 로직을 기다린다.)
await
은 async
함수 내의 일반함수에도 작성은 가능은 하다. (하지만 의미없는 행위이지 않나 싶다.)
function delayP(sec) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Date().toISOString());
}, sec * 1000);
});
}
async function asyncFunc() {
const time = await delayP(3);
return time;
}
asyncFunc().then(res => console.log('async 최종결과', res));
// 출력
// (3초뒤 아래 내용이 출력)
// async 최종결과 2021-08-14T14:00:50.295Z
어떤 함수내에서 비동기 작업의 값을 받아 와야할때 async/await
을 사용하면 유용하다.
어떤 함수 자체가 비동기 작업인 경우 Promise
를 리턴하게 만든다.
어떤 함수내에서 비동기 작업의 값을 받아 와야할때 async/await
을 사용한다.
Promise
를 리턴하는 함수, async/await
을 사용한 함수 모두 리턴값은 프로미스로 동일하므로 소비방식은 동일하다.