[TIL] Callback Function (2)

·2023년 10월 18일
0

TIL

목록 보기
9/85
post-thumbnail

콜백 지옥과 비동기 제어

  • 자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다.
  • 전통적인 콜백 패턴은 콜백 지옥으로 인해 가독성이 나쁘고, 비동기 처리 중 발생한 에러의 처리가 곤란하며 여러 개 비동기 처리를 한 번에 처리하는 데도 한계가 있다.

콜백 지옥이란?

  • 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 HELL 수준인 경우😂
  • 주로 이벤트 처리 및 서버 통신과 같은 비동기적 작업을 수행할 때 발생한다.
  • 가독성이 HELL 이어서 수정도 어렵다.

[동기 VS 비동기]

  • 동기 : synchronous
    • 현재 실행중인 코드가 끝나야 다음 코드를 실행하는 방식
    • CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드는 동기적 코드
    • 계산이 복잡해서 CPU가 계산하는 데 오래 걸리는 코드 역시 동기적 코드
  • 비동기 : asynchronous
    • 실행중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어가는 방식
    • setTimeout, addEventListener 등
    • 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 모두 비동기적 코드
    • 웹의 복잡도가 올라갈 수록 비동기적 코드의 비중이 늘어난다.

콜백 지옥의 예시와 해결 방안

setTimeout(
  function (name) {
    var 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,
  "에스프레소"
);

[실행결과]
에스프레소
에스프레소 , 아메리카노
에스프레소 , 아메리카노 , 카페모카
에스프레소 , 아메리카노 , 카페모카 , 카페라떼

  • 첫 번째 해결 방법은 기명 함수로 변환하는 것이다.
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, Generator (ES6), async / await (ES6) 가 그 예시 이다.

💡 비동기 작업의 동기적인 표현이 필요하다!

비동기 작업의 동기적 표현 (1) 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);
	});
});
  • refactoring 한 코드 ↓
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('카페라떼'));

비동기 작업의 동기적 표현 (2) Generator

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

비동기 작업의 동기적 표현 (3) 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();

느낀점

  • Promise, Generator, async / await 에 대해서는 각각 따로 글을 작성하면서 깊게 공부해봐겠다. 하나의 글에서 다 다루기에는 내용이 너무 많다 😵‍💫
  • 아직 다 이해했다고 말하기는 어려운 수준..

오늘 한 일

  • 오늘 드디어 조장을 뽑고, 개인 프로젝트를 시작했다. 조장 지원자가 아무도 없어서 결국 내가 자원했다.😇 ( 발표 하실 분? 에 이이서.. 또.. )
  • 개인 프로젝트는 '영화 검색 사이트' 만들기!
  • 오늘 영화정보 오픈API (TMDB)에서 영화 데이터 가져와서 여러 장의 영화 카드를 화면에 띄우는 것 까지 성공했다! (poster_path, title, overview, vote_average)

내일 할 일

  • API로 받아온 영화 중 input 에 입력한 문자값이 포함되는 영화들만 화면에 보이도록 하는 부분 구현
  • 카드 클릭 시 클릭한 영화 id 나타내는 alert 창 띄우기
profile
느리더라도 조금씩, 꾸준히

0개의 댓글