콜백 함수
: 다른 코드의 인자로 넘겨주는 함수
콜백 함수를 사용하는 것은 알람시계를 세팅하는 것과 같다.
시계의 알람을 설정하는 함수를 호출했고, 해당 함수는 호출 당시에는 아무것도 하지 않다가 B가 정해준 시각이 됐을 때 비로소 '알람을 울리는' 결과를 반환한다.
즉 시계 함수에게 요청을 하면서 알람을 울리는 명령에 대한 제어권을 시계에게 넘겨준 것이다.
콜백 함수는 제어권과 관련이 깊다.
이처럼 콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행할 것이다.
let count =1; let cbFunc = function (){ console.log(count); if(++count > 5) clearInterval(timer); }; let timer = setInterval(cbFunc, 1000); // -- 실행 결과 -- // 1 // 2 // 3 // 4 // 5
timer
변수에는 setInterval
의 ID 값이 담긴다.setInterval
에 전달한 첫 번째 인자인 cbFunc
함수는 1초마다 자동으로 실행될 것이다.count
값을 출력하고, count
를 1만큼 증가시킨 다음, 그 값이 4보다 크면 반복 실행을 종료한다.이처럼 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가진다.
let newArr = [10, 20, 30].map(function(currentValue, index){ console.log(currentValue, index); return currentValue + 5; }); console.log(newArr); // -- 실행 결과 -- // 10 0 // 20 1 // 30 2 // [ 15, 25, 35 ]
let newArr2 = [10, 20, 30].map(function(index, currentValue){ console.log(index, currentValue); return currentValue + 5; }); console.log(newArr2); // -- 실행 결과 -- // 10 0 // 20 1 // 30 2 // [ 5, 6, 7 ]
index
, currentValue
순서를 바꾸더라도 각 단어의 의미가 바뀌지 않으니까 문제 없을 것이라고 생각하기 쉽지만, 저 단어들은 사용자가 명명한 것일 뿐이다.let obj = { vals : [1, 2, 3], logValues : function(v, i) { console.log(this, v, i); } }; obj.logValues(1,2); [4, 5, 6].forEach(obj.logValues); // -- 실행 결과 -- //{ vals: [ 1, 2, 3 ], logValues: ƒ logValues() } 1 2 //Window {...} 4 0
obj.logValues(1,2);
: this
는 obj
를 가리키고, 인자로 넘어온 1, 2가 출력된다.[4, 5, 6].forEach(obj.logValues);
: forEach에 의해 콜백이 함수로서 호출되고 , 별도로 this를 지정하는 인자를 지정하지 않았으므로 함수 내부에서의 this
는 전연객체를 바라보게 된다.동기적
인 코드는 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식이다. 반대로 비동기
적인 코드는 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어간다. CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드는 동기적
인 코드다. 반명 사용자의 요청에 의해 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 `비동기적
인 코드다.
웹의 복잡도가 높아진 만큼 비동기적인 코드의 비중이 예전보다 훨씬 높아진 상황이다. 그와 동시에 콜백 지옥에 빠지기도 훨씬 쉬워졌다.
setTimeout(function (name) { let coffeeList = name; console.log(coffeeList); setTimeout(function (name) { coffeeList += ', '+name; console.log(coffeeList); setTimeout(function (name) { coffeeList += ', '+name; console.log(coffeeList); setTimeout(function (name) { coffeeList += ', '+name; console.log(coffeeList); }, 500, '카페라떼'); }, 500, '카페모카'); }, 500, '아메리카노'); }, 500, '에스프레소'); // -- 실행 결과 -- //'에스프레소' //'에스프레소, 아메리카노' //'에스프레소, 아메리카노, 카페모카' //'에스프레소, 아메리카노, 카페모카, 카페라떼'
new Promise(function (resolve) { setTimeout(function(){ var name = '에스프레소'; console.log(name); resolve(name); },500); }).then(function(prevName) { return new Promise(function (resolve) { setTimeout(function(){ var name = '아메리카노'; console.log(name); resolve(name); },500); }); }).then(function(prevName) { return new Promise(function (resolve) { setTimeout(function(){ var name = '카페모카'; console.log(name); resolve(name); },500); }); }).then(function(prevName) { return new Promise(function (resolve) { setTimeout(function(){ var name = '카페라떼'; console.log(name); resolve(name); },500); }); }); // -- 실행 결과 -- //'에스프레소' //'아메리카노' //'카페모카' //'카페라떼'
Promise
의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행되지만 내부에 resolve
또는 reject
함수를 호출하는 구문이 있을 경우then
또는 catch
로 넘어가지 않는다.resolve
또는 reject
를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능하다.