자바스크립트에서 여러 함수들을 사용하면 비동기 동작을 스케줄링할 수 있습니다. 즉, 원하는 때에 동작을 시작하게 할 수 있죠.
그리고 스케줄링에서 가장 대표적인 함수가 setTimeout
인데,
실무에선 더 많은 비동기 동작 함수가 있는데, loadScript
로
예를 들어보겠습니다.
function loadScript(src) {
// <script> 태그를 만들고 페이지에 태그를 추가합니다.
// 태그가 페이지에 추가되면 src에 있는 스크립트를 로딩하고 실행합니다.
let script = document.createElement('script');
script.src = src;
document.head.append(script);
}
이 스크립트는 비동기적으로 실행됩니다. 왜냐하면 시작되더라도 실행은 함수가 끝난 후에 되기 때문인데요.
이때문에 발생한 에러 중 하나는
loadScript('/my/script.js');
// script.js엔 "function newFunction() {…}"이 있습니다.
newFunction();
// 함수가 존재하지 않는다는 에러가 발생합니다!
이런 에러 입니다. 함수를 긁어오는 동안 함수를 찾으니 함수는 없다고 인식되고
함수는 써야하는데 말이죠.
이럴 경우, 콜백 함수를 추가한다면 해결할 수 있습니다.
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}
콜백 함수는 나중에 호출할 함수를 의미하고, 위처럼 사용하면 에러가 발생하지 않습니다.
이런 방식으로 콜백 기반 비동기 프로그래밍이라고 하는데,
뭔가를 비동기적으로 수행하는 함수는 함수 내 동작이 모두 처리되어야하는 함수가 들어갈 콜백을 인수로 제공해야합니다.
위 loadScript
에서 콜백 제공하는 방식이 일반적인 접근법입니다.
아까 사용했던 loadScript
에서, 스크립트 두 개를 순차적으로 불러오려면
콜백 함수 안에서 두 번째 loadScript
를 호출해야합니다.
loadScript('/my/script.js', function(script) {
alert(`${script.src}을 로딩했습니다. 이젠, 다음 스크립트를 로딩합시다.`);
loadScript('/my/script2.js', function(script) {
alert(`두 번째 스크립트를 성공적으로 로딩했습니다.`);
});
});
이런 코드에 에러 핸들링까지한다면,
loadScript('1.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('2.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('3.js', function(error, script) {
if (error) {
handleError(error);
} else {
// 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*)
}
});
}
})
}
});
보기 흉측한 코드가되고 이런 중첩코드는 콜백 지옥이라 불립니다.
비동기 동작 하나당 더 커진다면 이런 문제는 더 커집니다.
이런 코딩 방식보단, 각 동작을 함수로 만드는 것이 훨씬 좋습니다.
함수화 시키는 것 말고 프로미스라는 개념도 있습니다!