(Core JavaScript) 04. 콜백 함수 (2)

안녕하세요. 개발자 J입니다.

04. 콜백 기능

4-1 콜백 함수란?
4-2 제어권
4-3 콜백 함수는 함수다
4-4 콜백 함수 내부의 this에 다른 값 바인딩하기
4-5 콜백 지옥과 비동기 제어

4-3 콜백함수는 함수다

⇒ 콜백 함수로 어떤 객체의 메서드를 전달하더라도 방법 없음 기능라고!

메소드를 콜백 함수로 전달할 때

var obj = {
	vals: (1,2,3),
	logValuses: function(v, i) {
		console.log(this, v, i);
	}
};
obj.logValues(1, 2); // 메서드로서 호출 => this : obj
// {vals: (1, 2, 3), logValues: f} 1 2
(4, 5, 6).forEach(obj.logValues); // Window { ... } 4 0 -> 5 1 -> 6 2

4-4 콜백 함수 내에서 다른 값을 바인딩합니다.

콜백 함수 내에서 다른 값을 바인딩하는 방법 → 기존 방식

var obj1={
	name:'obj1',
	func: function(){
		var self = this; 
		return function(){
			console.log(self.name); //this == self == obj1
		};
	}
};
var callback = obj1.func();
setTimeout(callback,1000); // 출력 : obj1

콜백 함수 내에서 사용하지 않는 경우

var obj1={
	name: 'obj1',
	func: function(){	
		console.log(obj1.name); 
	}
};
setTimeout(obj1.func,1000);

⇒ 이와 다른 상황에서 재활용 불가 (보려는 개체를 obj1로 명시적으로 지정하여)

func 함수를 재사용할 수 있습니다.

...
var obj2={
	name: 'obj2',
	func: obj1.func
};
var callback2 = obj2.func();
setTimeout(callback2,1500); // obj2

var obj3 = {name: 'obj3'};
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000); // obj3

⇒ 방법이 번거롭지만 간접적으로 사용다양한 상황에서 원하는 객체를 바라보는 콜백 함수 생성 가능


4-5 콜백 지옥과 비동기 제어

지옥을 회상하다 : 콜백함수를 익명함수에 넘기는 과정이 반복되면서 코드의 들여쓰기 수준이 참을 수 없을 정도로 깊어지는 현상.

비동기 동기

  • 동기 부여적대적인 코드 : 현재 실행 중인 코드가 완료된 후오 다음 코드를 실행하는 방법
    • 예) 대부분의 코드는 CPU 연산으로 즉시 처리 가능
  • 비동기암호 : 현재 실행 중인 코드가 완전한지 여부에 관계없이. 다음 코드로 바로 이동
    • setTimeout, addEventListener, XMLHttpRequest 등
    • 별도의 요청, 실행 대기, 보류 등과 관련된 코드

지옥을 회상하다

setTimeout(function (name)){  //  ---- (4)
	var coffeeList = name;
		console.log(coffeeList);

		setTimeout(function (name)){  // ---- (3)
		  coffeeList += ',' + name;
			console.log(coffeeList);

			setTimeout(function (name)){  // ---- (2)
			  coffeeList += ',' + name;
				console.log(coffeeList);
	
				setTimeout(function (name)){  // ----(1)
				  coffeeList += ',' + name;
					console.log(coffeeList);
				},500,'카페라떼');
			},500,'카페모카');
		},500,'아메리카노');
},500,'에스프레소');

→ 0.5초마다 커피 목록을 모아서 출력하는 코드

⇒ 가독성 문제 및 어색함 수정: 모든 익명 콜백 함수 명명된 함수로 전환

콜백 지옥 해결 – 명명된 함수로 변환

var coffeeList="";

var addEsspresso = 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

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);
	});
});

⇒ new 연산자로 호출된 promise의 인수로 전달된 콜백 함수는 호출 시 실행되지만 해결 또는 거부 기능다음(then) 또는 오류(catch) 문 중 하나가 실행될 때까지 진행되지 않습니다.

Asynchronous Work의 Synchronous 표현 – Promise ⇒ Iterative Content의 함수로 표현되는 Shortcode

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('카페라떼'))

비동기 작업의 동기식 표현 – 생성기

var addCoffee = function(prevName, name) {
	setTimeout(function() {
		coffeeMaker.next(prevName ? prevName + ', ' + name : name);
	}, 500);
};
var coffeeGenerator = function* () { // '*'이 붙은 함수 -> Generator 함수
	var espresso = yield addCoffee('', '에스프레소');
	console.log(espresso);
	var americano = yield addCoffee(espresso, '아메리카노');
	console.log(americano);
	var mocha = yield addCoffee(americano, '카페모카');
	console.log(mocha);
	var latte = yield addCoffee(mocha, '카페라떼');
	console.log(latte);
};
var coffeeMaker = coffeeGenerator();
coffeeMaker.next();

생성기 기능을 실행할 때 이터레이터 반환 ⇒ 이터레이터는 다음 방법호출됨은 제너레이터 함수 내부에 가장 먼저 나타나는 것입니다. 생산하다에서 함수 실행을 중지합니다.

비동기 작업의 동기 표현 – Promise + Async/await

var coffee = 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();

⇒ 비동기 작업을 수행하려는 함수 앞 비동기함수 내에서 실제 비동기 작업이 필요한 모든 곳. 예상하다다음 내용을 단순히 표기만 하면 Promise로 자동 변환하고 내용이 해결된 후에만 진행합니다.