만약 유튜브에서 동기적인 처리를 한다면 동영상을 불러오는 동안 사용자는 화면 상에서 아무 동작도 할 수 없게 된다.
하지만 비동기 처리를 한다면 동영상이 불러와지는 동안 스크롤을 내려 댓글을 보는 등의 다른 작업을 진행할 수 있다.
이제 비동기로 작업을 실행하는 것이 좋다는 것을 알게 됬으니, 이 비동기 처리를 어떻게 내 마음대로 조작할 수 있을지 다음부터 알아보겠다.
const somethingGonnaHappen = callback => {
waitingUntilSomethingHappens()
if(isSomethingGood) {
callback(null, something)
}
if(isSomethingBad) {
callback(something, null)
}
}
somethingGonnaHappen((err, data) => {
if(err) {
console.log('ERR');
return;
}
return data;
})
err
와 data
의 자리가 정해진 것은 아니나, 통상적으로 위와 같이 쓰이고 있다.
Callback hell의 발생 -> 가독성이 매우 떨어진다.
네트워크 요청, 파일 읽기, setTimeout 등..
이러한 callback 의 단점을 보완하기 위해서 나온 것이 있으니...바로 Promise!
클래스의 한 종류로서 new Promise
를 통해 인스턴스를 생성한다.
인스턴스를 생성할 때, 인자로 콜백함수를 받는데, 콜백함수의 인자로 resolve
와 reject
를 받는다.
아래에서 callback으로 작성된 코드를 promise를 사용해 재작성해보면서 둘의 차이점을 확인해보겠다.
const printString = (string, callback) => {
setTimeout (
() => {
console.log(string);
callback();
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () => {
printString('A', () => {
printString('B', () => {
printString('C' () => {})
})
})
}
printAll(); //실행
const printString = (string) => { //printString 함수에서 promise 인스턴스 생성
return new Promise((resolve, reject) => {
setTimeout(
() => {
console.log(string);
resolve(); //callback과 같은 역할
},
Math.floor(Math.random() * 100) + 1
)
})
}
const printAll = () => {
printString('A')
.then(() => { //resolve의 return 값으로 들어감
return printString('B')
})
.then(() => {
return printString('C')
})
}
printAll() // 실행
이제 Promise에서 사용되는 용어(문법)에 대해 아래에서 알아보겠다.
resolve
, reject
** 새로운 인스턴스가 생성될 때, 자동으로 실행이 되므로 주의가 필요하다
const promise = new Promise((resolve, reject) => {
console.log('doing something');
setTimeout(() => {
// resolve('ellie'); //callback의 역할과 같음
reject(new Error('no network'); //error handling
}, 2000);
});
then
, catch
, finally
promise
.then(value => {
console.log(value);
})
.catch(error => { //error handling, then chaining 가장 마지막에 사용한다.
console.log(error);
})
.finally(() => {
console.log('finally') //앞의 내용이 실패하든 성공하든 무조건 실행된다.
})
Promise에서는 resolve
의 인자를 then
chaining을 사용해 넘길 수 있다.
State : pending(대기) -> fulfilled(완료) or rejected(에러)
Promise.all
callback hell을 보완하기 위해 고안된 promise 였지만....이 또한 hell 이 존재하였으니....
그리하여 나온 것이 async, await 문법입니다. 아래에서 살펴보겠습니다.
async
, await
프로미스를 간결,간편하게 사용하도록 하고 동기적으로 실행되는 것처럼 보이게 만들어주는 친구.
프로미스는 여러가지 체이닝 가능한데(then), 이 체이닝이 계속되면 코드가 복잡해질 수 있다.
이걸 해결하기 위해 나온 것이 async
, await
새로운 것이 추가 된 것이 아닌 기존에 존재하던 promise 위에 조금 더 간편한 api를 제공한 것이다.
이러한 것을 syntactic sugar라고도 한다. (= class, prototype 위에 그럴듯하게 씌워진 것)
프로미스를 사용할 때 반드시 async
, await
을 사용하라는 것은 아니고, 상황에 맞게 적절하게 사용하면 된다.
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('1. go to codestates')}, 100)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('2. sit and code')}, 500)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('3. eat lunch')}, 300)
})
}
function goToBed() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('4. go to bed')}, 400)
})
}
const result = async () => {
const one = await gotoCodestates();
console.log(one);
const two = await sitAndCode();
console.log(two);
const three = await eatLunch();
console.log(three);
const four = await goToBed();
console.log(four);
}
result(); //실행
포토샵 응답없음. -> blocking , 동기적인 작업에서 일어남
progress bar -> non - blocking , 비동기
v8엔진을 사용하는 시스템에서는 블라킹 = 동기, 논블라킹 = 비동기
그러낭 다른 엔진을 사용하는 곳에선 아닐 수 있음.
참고
읽을거리