얼마전 멘토링 과제로 자바스크립트의 비동기 처리와 콜백 함수에 관해 공부해보라는 과제를 받게 되었습니다.
그리고 평소 js를 공부하고 있었는데 처음 들어보는 용어들이라 호기심이 생겨 이렇게 블로그에 기재를 해보게 되었습니다.
그럼 바로 동기와 비동기의 개념부터 차근히 시작해보자구요!
자바스크립트는 한 번에 하나의 작업을 수행합니다.
마치 마트에서 장을 본 사람들이 한 사람씩 결제하는 것과 유사합니다.
이러한 동작은 단일 스레드(싱글 스레드), 즉 동기라고 부릅니다.
동기 : 한 작업이 실행되는 동안 다른 작업은 멈춘 상태를 유지하고 자신의 차례를 기다리는 것
동기를 코드로 이해해봅시다.
function first() {
second();
console.log("첫 번째");
}
function second() {
third();
console.log("두 번째");
}
function third() {
console.log("세 번째");
}
first();
third();
위의 예제를 실행해보면
세 번째
두 번째
첫 번째
세 번째
가 출력이 될 겁니다.
이렇게 동기적으로 동작하는 코드는 작성된 순서에 따라 진행되므로 작업의 흐름을 파악하기가 쉽죠.
다만 한 가지 문제점이 있습니다.
동기적으로 동작하는 코드는 순서대로 작업이 진행되기 때문에 시간이 오래 걸리는 코드가 앞 쪽에 위치한다면 전체적인 코드의 진행이 느려진다는 단점이 있습니다.
console.log("시작");
// 느린 코드
// 빠른 코드
위의 코드를 보면 "시작"이 출력된 후 느린코드가 빠른 코드 앞에 위치해 빠른코드의 실행 시작 또한 늦추고 있는 것을 알 수 있습니다.
그래서 이러한 동기적인 코드의 문제점을 해결하기 위해 비동기라는 개념이 존재합니다.
이전에 말했듯 자바스크립트는 단일 스레드, 동기식으로 동작합니다.
하지만 비동기는 어떠한 요청을 보내면 그 요청이 끝날 때까지 기다리는 것이 아니라, 응답에 관계없이 바로 다음 동작이 실행되는 방식을 말합니다.
비동기 : 어떠한 요청을 보내면 그 요청이 끝날 때까지 기다리는 것이 아니라, 응답에 관계없이 바로 다음 동작이 실행되는 방식
그렇다면 비동기는 왜 필요할까요?
바로 앞에서 말했던 동기적인 코드의 문제점을 해결하기 위해 존재합니다.
웹페이지가 로딩되거나, 어떠한 동작 하나가 30초 이상이 걸린다고 상상해보죠.
그렇게 되면 웹페이지는 동작 하나가 끝날 때까지 화면에 나타나지 않거나 다음 동작을 하는 데 지장을 주게 되겠죠.
사용자들은 당연히 답답해하며 웹페이지를 꺼버릴 것입니다.
그렇기 때문에 자바스크립트가 웹사이트에서 동작할 때 비동기적으로 처리할 수 있어야 하는 것입니다.
웹사이트를 들어가는 데에 30초 이상이 걸리고 여는 것 외에는 아무 동작도 할 수 없다면 너무 답답하지 않겠나요?
그렇다면 비동기적인 코드는 어떨까요?
console.log("시작");
setTimeout(function () {
console.log("중간");
}, 5000);
console.log("끝");
혹시 동기적으로 생각해서 아래와 같은 결과값을 기대하지는 않으셨나요?
시작 중간 끝
비동기적으로 처리하는 대표적인 함수 setTimeout
은 브라우저 제공 API이므로 Web API로 들어간 뒤 console.log("끝");
이 출력된 후 console.log("중간");
이 출력되게 됩니다.
이 부분은 비동기 작동 원리를 알아야 하는 부분이니 나중에 따로 정리하여 포스팅하겠습니다.
콜백 함수는 파라미터로 전달받은 함수를 의미합니다.
콜백 : 함수를 매개변수로서 다른 함수에 전달하고 감싼 함수의 내부에서 해당 함수를 호출합니다.
function callback() {
console.log("콜백 함수군요!");
}
function print(callback) {
callback();
}
print(callback);
print()
함수의 매개변수로 객체인 함수를 넘겨주었더니 정상적으로 메시지가 출력되는 모습을 확인할 수 있습니다.
function print(result) {
console.log(result);
}
function add(n1, n2, print) {
print(n1+n2);
}
add(10,20, print);
add
함수가 호출됩니다.add
함수에 파라미터로 전달된 print
의 매개변수로 n1
과 n2
의 합을 전달합니다.print()
함수가 호출됩니다.n1+n2
의 값을 출력합니다.function add(x, y, print) {
print(x + y)
}
add(10, 20, (result) => {
console.log(result)
})
add()
함수가 호출됩니다.10
과 20
과 print
가 전달됩니다.print
는 아래의 내장 함수와 같습니다. 10+20
의 결과를 콜백함수의 파라미터로 전달합니다.result
의 값이 30
을 받고 출력합니다.콜백 함수를 사용하면 다음과 같은 이점이 있습니다.
하지만 다음과 같은 단점 또한 존재합니다.
function print(callback) {
setTimeout(callback, 1000);
console.log("1초 기다려~");
}
print(() => {
console.log("Hello");
})
print()
함수가 호출됩니다.print()
함수의 매개변수인 print
에는 익명함수가 전달됩니다.setTimeout
은 비동기적 함수이므로 Web API
에 넘어가 "1초 기다려~"가 먼저 출력된 후 "Hello"가 출력됩니다. function study(time) {
if ( time === 1) {
setTimeout(() => {
console.log(time+"시간만큼 공부한거야?");
}, 1000);
} else if ( time === 3) {
setTimeout(() => {
console.log(time+"시간만큼 공부한거야?");
}, 3000);
} else if ( time === 5) {
setTimeout(() => {
console.log(time+"시간만큼 공부한거야?");
}, 5000);
} else if ( time === 10) {
setTimeout(() => {
console.log(time+"시간만큼 공부한거야?\n");
console.log("대단하네~");
}, 10000);
}
}
study(10);
study(5);
study(3);
study(1);
동기적으로 보면 10
시간부터 1
시간까지 내림차순으로 출력될 것 같지만 setTimeout
은 비동기처리 함수이기 때문에 아래와 같은 출력 결과가 나옵니다.