JS는 기본적으로 비동기적 방식
을 사용하기 때문에, 작업이 순차적으로 실행되어야 하는 경우 함수가 원치않는 순서로 실행되어 결과가 뒤바뀔 수 있다. 함수는 기본적으로 동기 방식을 사용하므로, 이를 콜백형태로 사용해 동기방식으로 프로그래밍 할 수 있다.
taskA, taskB, taskC 모두 setTimeout를 사용한 비동기 함수이다.
아래는 taskA, taskB, taskC 를 순차적으로 실행시킨 코드이다.
function taskA(num1, num2) {
setTimeout(() => {
const res = num1+num2;
console.log("task A : ", res)
}, 3000);
}
function taskB(num) {
setTimeout(() => {
const res = num * 2;
console.log("task B : ", res)
}, 1000)
}
function taskC(num) {
setTimeout(() => {
const res = num * -1;
console.log("task C : ", res)
}, 2000);
}
taskA(1,1);
taskB(1);
taskC(1);
/* 결과
task B : 2
task C : -1
task A : 2
*/
결과적으로 taskA가 끝난 후 taskB 그리고 taskC가 실행되지 않았다. taskA, taskB, taskC는 동시에 실행이 되었다. 이는 비동기적 방식은 동기적 방식처럼 call stack에 의해 순서대로 실행되지 않고 web APIs를 통해 동시에 실행이 되기 때문이다.
taskA, taskB, taskC 모두 setTimeout를 사용한 비동기 함수이다.
아래는 taskA, taskB, taskC 를 순차적으로 실행시킨 코드이다.
function taskA(a, b, callback) {
setTimeout(() => {
const res = a+b;
callback(res)
}, 3000);
}
function taskB(a, callback) {
setTimeout(() => {
const res = a * 2;
callback(res)
}, 1000)
}
function taskC(a, callback) {
setTimeout(() => {
const res = a * -1;
callback(res);
}, 2000);
}
taskA(1, 1, (a_res) => {
console.log("task A : ", a_res)
taskB(a_res, (b_res) => {
console.log("task B : ", b_res)
taskC(b_res, (c_res) => {
console.log("task C : ", c_res)
})
})
})
/* 결과
// 3초 후 >>> task A : 2
// 1초 후 >>> task B : 4
// 2초 후 >>> task C : -4
*/
콜백함수에 의해 taskA, taskB, taskC가 동기적으로 실행이 되었으며 setTimtout의 스코프에 있는 값에도 접근이 가능하다.
콜백 지옥
은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상을 얘기합니다. 주로 이벤트 처리나 서버 통신과 같은 비동기적인 작업을 수행하기 위해 이런 형태가 자주 등장하는데, 가독성이 떨어지면서 코드를 수정하기 어렵습니다.
function taskA(a, b, callback) {
setTimeout(() => {
const res = a+b;
callback(res)
}, 3000);
}
function taskB(a, callback) {
setTimeout(() => {
const res = a * 2;
callback(res)
}, 1000)
}
function taskC(a, callback) {
setTimeout(() => {
const res = a * -1;
callback(res);
}, 2000);
}
...
taskA(1, 1, (a_res) => {
console.log("task A : ", a_res)
taskB(a_res, (b_res) => {
console.log("task B : ", b_res)
taskC(b_res, (c_res) => {
console.log("task C : ", c_res)
taskD(c_res, (d_res) => {
console.log("task D : ", d_res)
taskE(d_res, (e_res) => {
console.log("task E : ", e_res)
taskF(e_res, (f_res) => {
console.log("task F : ", f_res)
...
})
})
})
})
})
})