콜백
비동기적 처리에 대해서
1 2 3 4 5 6 7
| function loadScript(src) { let script = document.createElement('script'); script.src = src; document.head.append(script); }
|
1 2
| loadScript('/my/script.js');
|
loadScript 는 비동기적으로 실행된다.
loadScript()
아래에 있는 코드들은 loadScript 가 실행되는 것을 기달려 주지 않고 바로 실행 됨.
1 2 3
| loadScript('/my/script.js');
newFunction();
|
newFunction은 loadScript 안에 있으니가 아직 생성 되지 않았을 것이다.
현재로서는 loadScript가 완료 됬는지 알 수 있는 방법이 없다.
loadScript가 완료되면 원하는 함수를 실행 시키기 위해서 콜백 함수를 추가 행야 한다.
1 2 3 4 5 6 7 8
| function loadScript(src, callback) { let script = document.createElement('script'); script.src = src;
script.onload = () => callback(script);
document.head.append(script); }
|
1 2 3 4 5
| loadScript('/my/script.js', function() { newFunction(); ... });
|
실제 사용 예시
1 2 3 4 5 6 7 8 9 10 11
| function loadScript(src, callback) { let script = document.createElement('script'); script.src = src; script.onload = () => callback(script); document.head.append(script); }
loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => { alert(`${script.src}가 로드되었습니다.`); alert( _ ); });
|
무언가 비동기적으로 처리되는 함수는 처리가 끝난 이후 동작할 함수를 반드시 인수로 제공해야 한다.
콜백 속 콜백
첫번째 스크립트를 읽은후 순차적으로 스크립트를 읽고 싶다면 어떻게 처리해야 할까?
콜백 함수 안에 두번째 loadScript를 호출하면 된다.
1 2 3 4 5 6 7 8 9
| loadScript('/my/script.js', function(script) {
alert(`${script.src}을 로딩했습니다. 이젠, 다음 스크립트를 로딩합시다.`);
loadScript('/my/script2.js', function(script) { alert(`두 번째 스크립트를 성공적으로 로딩했습니다.`); });
});
|
만약 3개라면?
1 2 3 4 5 6 7 8 9 10 11
| loadScript('/my/script.js', function(script) {
loadScript('/my/script2.js', function(script) {
loadScript('/my/script3.js', function(script) { });
})
});
|
만약 갯수가 굉장히 많아진다면??
이렇게 작성히는 것은 적을때는 가능하지만 많을때는 좋은 방법이 아니다..
에러 핸들링
스크립트 로딩이 실패했을때 에러 핸들링 추가
1 2 3 4 5 6 7 8 9
| function loadScript(src, callback) { let script = document.createElement('script'); script.src = src;
script.onload = () => callback(null, script); script.onerror = () => callback(new Error(`${src}를 불러오는 도중에 에러가 발생했습니다.`));
document.head.append(script); }
|
사용
1 2 3 4 5 6 7
| loadScript('/my/script.js', function(error, script) { if (error) { } else { } });
|
이런 패턴을 오류 우선 콜백(error-first callback)
이라고 한다.
첫 번째 인수는 에러를 위해 남겨 둔다. 두번재 부터 여러개 추가 할 수 있음. 이렇게 하면 에러 케이스와 성공 케이스 모두 처리 가능하게 된다.
멸망의 피라미드
언뜻 좋아 보이지만 여러개가 반복되면 콜백 지옥이 발생한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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 { } });
} }) } });
|
각 동작을 독립적인 함수로 만들어 완화하도록 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| loadScript('1.js', step1);
function step1(error, script) { if (error) { handleError(error); } else { loadScript('2.js', step2); } }
function step2(error, script) { if (error) { handleError(error); } else { loadScript('3.js', step3); } }
function step3(error, script) { if (error) { handleError(error); } else { } };
|
사실 이렇게 작성해도 보기 불편한건 사실이고, 함수를 만들었는데 단지 콜백 지옥을 피하기 위해서만 만들었기 때문에 재사용이 불가능하다.
가장 좋은 방법은 프로 미스를 사용하는 방법인데 다음 포스팅에서 설명하도록 한다.