TIL | [React]그냥 코드 풀면서 그때 그때 callback해서 익힐게요...

레이나·2025년 1월 4일

Today I Learned

목록 보기
23/47
post-thumbnail

[250104 토요일]

코드작성을 하면서 알게모르게 사용해 왔던 콜백함수.
자세히 들여다보니 머리가 아프다.. 그냥 사용할 때가 더 쉬운느낌이 뭘까?
배웠으니 나중에 찾아보기 편하게 정리는 하겠지만..
이게 콜백함수다~ 재귀다~ 이런걸 생각하고 작성하는것보다, 생각을 안하고 코드 작성하고 나서 리뷰하면서 뜯어보는게 이해가 더 잘되요..

✔︎ 콜백함수 특징

  • 다른 코드의 인자로 넘겨주는 함수
  • 콜백함수를 받은 주체가 되는 함수에게 콜백함수의 실행 제어권과 인자의 순서까지도 제어권이 있다.
  • 동기과 비동기가 있으며 비동기는 동기처럼 되도록 리팩토링 필요.
  • 콜백함수도 함수이기 때문에 기본적으로 this를 받을 경우 전역개체를 바라본다.
  • 제어권을 넘겨받을 코드(콜백함수의 코드)에서 call, apply 메서드의 첫 번째 인자에서 콜백함수 내부에서 사용될 this를 명시적으로 바인딩하기 때문에 이렇게 별도로 this(bind포함) 대상을 지정한 경우 그 대상을 참조한다.
  • 콜백함수로써 객체의 메서드 전달시, 메서드가 아닌 함수로 호출됨
var obj = {
	vals: [1, 2, 3],
	logValues: function(v, i) {
		console.log(this, v, i);
	}
};
//-------
//method로써 호출
obj.logValues(1, 2);
//
//callback => obj를 this로 하는 메서드를 그대로 전달한게 X
// 매개변수로 넣어줄떄는 함수 자체로 넣어줘야함
//단지, obj.logValues가 가리키는 함수만 전달(obj 객체와는 연관 X)
[4, 5, 6].forEach(obj.logValues);
//
//위의 내용을 풀어서 보면 아래와 같다.
[4, 5, 6].forEach(function(v, i) {
		console.log(this, v, i);
	});

✔︎ 동기, 비동기

  1. 비동기 : a + synchronous ⇒ async
    a. 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어가는 방식
    b. setTimeout, addEventListner 등
    c. 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 모두 비동기적 코드
  1. 동기 : synchronous
    a. 현재 실행중인 코드가 끝나야 다음 코드를 실행하는 방식
    b. CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드는 동기적 코드
    c. 계산이 복잡해서 CPU가 계산하는 데에 오래 걸리는 코드 역시도 동기적 코드

순서를 보장할 수 없는 코드를 손서를 보장할 수 있게 해기 위해 비동기 처리를 동기적으로 변환

🔹 Promise

비동기 작업은 처리 순서를 보장하지 않기 때문에 처리가 끝나면 알려달라는(resolve:성공 / reject:실패) 약속이다.

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

위 코드를 실행하면 아래와 같은 결과가 나온다.
Espresso
Espresso, Americano
Espresso, Americano, CafeMocha
Espresso, Americano, CafeMocha, CafeLatte

커피이름이 계속해서 바뀌고 출력된다. setTimeout함수이기 때문에 딜레이 시간이 있다. 이때 다음 과정이 바로 진행되는 것이 아니라 로직이 완수될 때 까지 기다렸다가 성공(resolve)하면 그 다음(then) 로직으로 이어가는 promise를 만든것이다.


🔹 generator*

  • *가 붙은 함수가 제네레이터 함수
  • 반복할수 있는 Iterable 객체를 생성
  • yeild로 다음 과정을 일시적으로 멈춘다.
  • 프로미스의 then 처럼 next를 호출, 다음 yield까지 진행
var addCoffee = function (prevName, name) {
	setTimeout(function () {
		coffeeMaker.next(prevName ? prevName + ', ' + name : name);
	}, 500);
};
var coffeeGenerator = function* () {
	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();

🔹 async, await

  • promise를 반환하는 함수와 같이 사용됨
  • 함수 앞에 async를 붙여 비동기식을 알리고 await를 만나면 해당로직이 끝날 때 까지 대기.
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();

앞전 호이스팅, 얕은복사, 깊은복사 보다는 이해하기 쉬운 편이긴 하였으나, 예제나 과제를 풀어보니 생각만큼 쉬운 녀석은 아니었다.
너도 자주 보자!

profile
one setp

0개의 댓글