반응형
콜백 함수
- 콜백 함수란?
- 다른 코드(함수 || 메서드)의 인자로 넘겨주는 함수
- 제어권도 함게 위임함
제어권
- 호출 시점
- setInterval
- scope : Window 객체 || Worker의 인스턴스
- 브라우저 환경에서는 window를 생략해서 함수처럼 사용 가능
- 세번째 매개변수
- 선택적
- func 함수를 실행할 때 매개변수로 전달할 인자
- 어떠한 값도 리턴하지 않음
- 고유한 ID값 반환 ⇒ clearInterval(중간 종료)를 위해
var count = 0; var cbFunc = function() { console.log(count); if(++count > 4) clearInterval(timer); }; var timer = setInterval(cbFunc, 300); //실행 결과 //0 (0.3초) //1 (0.6초) //2 (0.9초) //3 (1.2초) //4 (1.5초)
- timer 변수 : setInterval의 ID값 담김
cbFunc(); 사용자 사용자 setInterval(cbFunc, 300); setInterval setInterval - scope : Window 객체 || Worker의 인스턴스
- var intervalID = scope.setInterval(func, delay[, param1, param2, ...]);
- setInterval
- 인자
- map
콜백 함수의 실행 결과를 모아 새로운 배열 생성
Array.prototype.map(callback [,thisArg]) callback : function(currentalue, index, array)
- 첫번째 인자 : callback 함수
- 두번째 인자(생략 가능) : 콜백 함수 내부에서 this로 인식할 대상 특정
- 콜백 함수의 인자
- 첫번째 인자 : 배열의 요소 중 현재 값
- 두번째 인자 : 현재값의 인덱스
- map 메서드의 대상이 되는 배열 자체
- 순서에 따라 값이 결정됨
- 변수명을 바꿔도 값은 동일함
- : 메서드의 대상이 되는 배열의 모든 요소들에 콜백 함수를 반복 호출
- map
- this
- 콜백 함수도 함수 ⇒ 기본적으로 this가 전역객체 참조
- 제어권을 넘겨받을 코드에서 별도로 this 지정 시, 그 대상 참조
- map 메서드 구현
Array.prototype.map = function(callback, thisArg) {
var mappedArr = [];
for(var i = 0; i < this.length; i++){
var mappedValue = callback.call(thisArg || window, this[i], i, this);
mappedArr[i] = mappedValue;
}
return mappedArr;
};
- this
- thisArg 값이 존재하는 경우 해당 값 지정
- 없을 경우 전역객체 지정
- call/apply 메서드의 첫번째 인자
- : 콜백 함수 내부에서 this가 될 대상을 명시적 바인딩
setTimeout(function() {console.log(this);},300); // (1) Window{...} // Timeout 객체가 나옴 [1, 2, 3, 4, 5]. forEach(function(x) { console.log(this); // (2) Window{...} }); document.body.innerHTML +='<button id="a">클릭</button>'; document.body.querySelector('#a') .addEventListener('click', function(e) { console.log(this, e); // (3) <button id ="a">믈랙</button> } //MouseEvent {isTrusted : tru, ...} };
콜백 함수 == 함수
- 메서드를 콜백 함수로 전달
var obj = { vals : [1, 2, 3], logValues : function(v, i) { console.log(this, v, i); } }; obj.logValues(1, 2); //{vals : [1, 2, 3], logValues : f} 1 2 [4. 5. 6].forEach(obj.logValues); //Window {...{} 4 0 //Window {...{} 5 1 //Window {...{} 6 2
- : 콜백 함수로 어떤 객체의 메서드를 전달하더라도 함수로서 호출
콜백 함수 내부의 this에 다른 값 바인딩하기
- 전통적 방식
- this를 다른 변수에 담아 콜백 함수로 활용할 함수에서 this 대신 변수를 사용
- 이를 클로저로 사용
//콜백 함수 내부의 this에 다른 값을 바인딩
var obj1 = {
name : 'obj1',
func : function() {
var self = this;
return function() {
console.log(self.name);
};
}
};
var callback = obj1.func();
setTimeout(callback, 1000);
//실제 this 사용 X + 번거로움
- 콜백 함수 내부에서 this를 사용하지 않은 경우
//콜백 함수 내부에서 this 사용 X
var obj1 = {
name : 'obj1',
func : function() {
console.log(obj1.name);
}
};
setTimeout(obj.func, 1000);
//this 재활용 불가
//다른 객체를바라보게 못함 => 메모리 낭비
- func 함수 재활용
var obj2 = {
name : 'obj2',
func : obj1.func
};
var callback2 = obj2.func();
setTimeout(callback2, 1500);
var obj3 = {name:'obj3'};
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000);
- 콜백 함수 내부의 this에 다른 값 바인딩 - this
var obj1 = {
name : 'obj1',
func : function() {
console.log(this.name);
}
};
setTimeout(obj1.func.bind(obj1), 1000);
var obj2 = {name : 'obj2'};
setTimeout(obj.func.bind(obj2), 1500);
- 콜백 지옥과 비동기 제어
- 콜백 지옥이란?
- 콜백 함수를 익명 함수로 전달되는 과정 반복
- ⇒ 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어짐
- 비동기 작업을 수행에 자주 등장
- 동기
- 현재 실행 중인 코드가 완료된 후에 다음 코드 실행
- CPU 계산에 의해 즉시 처리가 가능한 대부분의 코드
- 비동기
- 현재 실행 중인 코드의 완료 여부와 무관하게 다음 코드 실행
- ex(별도의 요청, 실행 대기, 보류)
- setTimeout
- : 사용자의 요청에 의해 특정 시간이 경과되기 전까지 어떤 함수의 실행 보류
- addEventListener
- : 사용자의 직접적인 개입이 있을 때 함수를 실행하도록 대기
- XMLHttpRequest
- : 별도의 대상에 요청(웹브라우저 자체 X) 후 응답이 왔을 때 함수 실행
- 동기
- 콜백 지옥 해결
- 콜백 지옥이란?
- 기명 함수 전환
- 코드의 가독성 높임
- 함수 선언과 호출 구분 시 순서대로 읽어가는데 어려움 없음
- 변수를 최상단으로 끌어올리며 외부에 노출 ⇒ 전체를 즉시 실행 함수 등 감싸 해결 가능
var coffeeList = ''; var addEspresso = function (name) { coffeeList = name; console.log(coffeeList); setTimeout(addAmericano, 500, '아메리카노'); }; var addAmericano = function (name) { coffeeList = name; console.log(coffeeList); setTimeout(addMocha, 500, '카페모카'); }; var addMocha= function (name) { coffeeList = name; console.log(coffeeList); setTimeout(addLatte, 500, '카페라떼'); }; var addLatte= function (name) { coffeeList = name; console.log(coffeeList); }; setTimeout(addEspresso, 500, '에스프레소');
- Promise
- ES6 도입
- new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행
- 내부의 resolve 또는 reject 함수를 호출하는 구문 존재
- 둘 중 하나가 실행되기 전까지 다음(then) 또는 오류(catch) 실행 X
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 = prevName + ', 아메리카노'; console.log(name); resolve(name); },500); }); }).then(function (prevName) { return new Promise(function (resolve) { setTimeout(function() { var name = prevNAme + ', 카페모카'; console.log(name); resolve(name); }, 500); }); }).then(function(prevName) { return new Promise(function (resolve) { setTimeout(function() { var name = prevName + ' 카페라떼'; console.log(name); resolve(name); }, 500); }); });
//반복적 내용의 함수화 var addCoffee = function(name) { return function (prevName) { //클로저 return new Promise(function (resolve) { //클로저 setTImeout(function() { var newName = prevName ? (prevName + ', ' + name) : name; console.log(newName); resolve(newName); }, 500); }); }; }; addCoffee('에스프레소')() .then(addCoffee('아메리카노')) .then(addCoffee('카페모카')) .then(addCoffee('카페라떼'));
- Generator
- ES6 도입
- Generator 함수 : * 붙은 함수
- 실행 시 Iterator 반환
- next 메서드 호출 시 Generator 함수 내부에 가장 먼저 등장하는 yield에서 함수 실행을 멈춤
- 이후 next 메서드 호출 시 멈췄던 부분 시작 ⇒ 다음 yield에서 실행 멈춤
var addCoffee = function(prevName, name) { setTimeout(function () { coffeeMaker.next(prevName ? prevName + ', ' + name : name); },500); }; var coffeeGenerator = function* () { //Generator var espresso = yield addCoffe('', '에스프레소'); console.log(espresso); var americano = yield addCoffe('', '아메리카노'); console.log(americano ); var mocha = yield addCoffe('', '카페모카'); console.log(mocha); var latte = yield addCoffe('', '카페라떼'); console.log(latte); }; var coffeeMaker = coffeeGenerator(); coffeeMaker.next();
- Promise + Async/await
- ES2017 도입
- async/await
- aynce
- : 비동기 작업을 수행하고자 하는 함수 앞에 표기
- await ⇒ 뒤의 내용 Promise 자동 전환
- ⇒ 해당 내용이 resolve 된 후에 다음으로 진행
- : 함수 내부에서 실질적ㅇ니 비동기 작업이 필요한 위치마다 표기
var addCoffee = function (name) { return new Promise(function (resolve) { setTimeout(function() { resolve(name); }, 500); }); }; var coffeeMaker = async function() { var coffeeList = ''; var _addCoffee = async function(name) { coffeeList += (coffeeList ? ',' : '') + await addCoffee(name); }; await _addCoffee('에스프레소'); console.log(coffeeList); await _addCoffee('아메리카노'); console.log(coffeeList); await _addCoffee('카페모카'); console.log(coffeeList); await _addCoffee('카페라떼'); console.log(coffeeList); }; coffeeMaker();
반응형