Javascript를 배우고 있습니다. 매일 배운 것을 이해한만큼 정리해봅니다.
SPA에서는 한 페이지 안에 다양한 기능이 존재하고, 한 기능이 실행 되었을 때 나머지 기능들이 동기적 실행이 완료 되기를 대기하며 작동하지 않으면 안된다. (카페에서 커피를 주문 받아 음료를 만들어 고객에게 전달한 후에야 다음 주문을 받는다면 카페 고객들은 경악할 것이다) 기능 실행 등 요청이 접수된 후에 비동기적인 작업이 진행되어야 다른 기능들도 한 웹앱 안에서 순조롭게 작동할 수 있게 된다.
자바스크립트는 싱글 스레드다. 외부의 데이터(외부의 api로 데이터를 받거나 보내는 등) 혹은 브라우저에서 제공하는 call api를 걸쳐 작업이 이뤄지는 경우(setTimeout, setInterval)에는 싱글 스레드 구조에서도 비동기적인 요청과 응답을 구현해야 한다.
비동기적 실행이라고 하지만 요청을 할 때 이야기이고, 요청이 실행되거나 요청에 대한 응답이 돌아왔을 때는 또 다시 순차적으로 명령이 수행되어야 한다.
예를 들어 유튜브에서 '먹방'이라고 검색하여 검색 결과를 받아오는 것은 비동기적으로 실행되어야 하지만 검색어 '먹방'으로 인해 도착한 검색 결과들을 다시 사용자에게 원하는 대로 가공해서 보여주기 위해서는 비동기 실행이 끝난 "후"에 그 결과를 가지고(여기가 매우 중요) 코드를 작성해 원하는 결과를 시각화 할 수 있다.
처음 비동기라는 개념을 배웠을 때는 비동기 실행의 결과를 받아 실행되는 또 다른 함수들을 이해하기 어려웠는데 생각해보면 처음은 비동기적 호출이었을지 모르나 일단 다시 원하는 호출 결과가 돌아온다면 그 때부터는 또 다시 의도적인 코딩 순서에 맞춰서 흐름을 타야 하는 건 너무 당연한 일인 것 같다.
이치적으로는 그러하나 일단 비동기로 발현한 것을 잡아와 다시 동기적 순서에 맞춰 가공하는 것이 쉽지는 않았을 것이다. 이를 보완하고자 아래와 같은 방법(callback → Promise객체 → Async/Await)들이 발전해 왔다.
function delay(callback) {
setTimeout(callback, 1000);
}
let arr = [];
delay(() => {
console.log(1)
arr.push(1);
delay(() => {
console.log(2)
arr.push(2);
delay(() => {
console.log(3)
arr.push(3);
delay(() => {
console.log(4)
arr.push(4);
delay(() => {
console.log(5)
arr.push(5);
delay(() => {
console.log(arr);
})
})
})
})
})
})
// 1
// 1초 뒤 2
// 1초 뒤 3
// 1초 뒤 4
// 1초 뒤 5
// 1초 뒤 마지막으로 [1,2,3,4,5] 로그가 찍힘
.then
이라는 method를 사용해서 비동기 처리 후 진행되어야 하는 순서를 구분해준다 프로미스 인스턴스에 담겨 있던 어떠한 값은 then 뒷 부분의 전달 인자로 주어진다. function deplayP(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n);
}, 1000);
});
}
delayP(1).then(result => {
console.log(result);
return delayP(2);
}).then(result => {
console.log(result);
return delayP(3);
}).then(result => {
console.log(result);
return delayP(4);
}).then(result => {
console.log(result)
return delayP(5);
}).then(result => {
console.log(result)
})
//1부터 1초씩 지나면서 1, 2, 3, 4, 5가 로그에 찍힌다.
function delayP(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n);
}, 1000);
});
}
async function myAsync() {
for(let n = 1; n < 6; n++) {
let result = await delayP(n);
console.log(result);
}
};
myAsync();
//1부터 1초씩 지나면서 1, 2, 3, 4, 5가 로그에 찍힌다.
이렇게 순차적으로 보면 async-await이 callback이나 Promise 방식보다 훨씬 좋아 보이지만, 그럼에도 3가지는 용도에 맞춰서 적절히 사용해야 한다. callback은 별 다른 키워드 없이도 구현할 수 있는 문법이기 때문에 콜백 지옥을 맞이할 정도의 복잡한 상황이 아닐 때 사용하면 좋다. callback 외 Promise나 Async-await 방식은 Promise 인스턴스로 전환되었다가 다시 돌아오는 작업을 거쳐야 하기 때문에 이 과정을 굳이 하지 않아도 되는 상황까지 고려했을 때 callback도 때에 따라선 좋은 답이 될 수 있다.
참고 자료
좋은 정보 감사합니다!