본문 바로가기
개발 기초 다지기

내일배움캠프 11일차 : 콜백지옥 해결 방법 동기/비동기

by 너의고래 2024. 4. 29.

지난번에 정리하던 콜백함수를 동기/비동기와 함께 마저 정리하려 한다.

 

  • 동기(synchronous) : 코드가 차례대로 실행되는 방식
  • 비동기(a + synchronous - async) : 실행중인 코드 완료와 상관 없이 다른 코드를 넘어가는 방식
    ex) setTimeout, addEventListner 등

 

- 콜백지옥을 해결하려면

콜백 지옥 : 콜백 함수를 익명의 함수로 전달하는 과정이 반복 됨으로 엄청난 들여쓰기가 발생한 상황 - 가독성 안좋음, 수정도 어렵

ex) 콜백지옥의 모습

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,
  "에스프레소"
);

 

-> 이 문제를 해결하려면 비동기 작업의 동기적 작업 필요

 

 

(1) Promise

: 비동기 처리에 대해 일이 끝나면 알려달라는 약속

- Promise의 인자로 호출된 함수는 바로 실행됨

- 그 안의 resolve 또는 reject 함수 호출 시 이것들이 실행완료 되기 전까지 then 이나 catch로 넘어가지 않음

 

///비동기 -> 동기적 표현

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

 

(2) Generator

: '*'이 붙은 함수로, 실행하면 iterator객체가 반환'next()'을 가지고 있으면 됨

- iterator은 next 메소드로 순환 할 수 있는 객체로,
   next메서드 호출 시 Generator 함수 내부에 가장 먼저 있는 'yield'에서 멈춘 후 다시 next 메서드 호출 시 다음 yield까지 실행 후 멈춤

- 비동기 완료 시점마다 next 메서드 호출 시 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) Promise + Async/await

  • Async함수 : 비동기 작업을 수행하려고하는 함수 앞에 붙임
  • await : 실질적인 비동기 작업이 필요한 곳에 붙임

Promise ~ then과 동일 효과

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

 

 

개념 내용과 기본적인 예시를 통해 배워서 지금은 이해가 가는 것 같은데 막상 내가 코딩을 할 때 이용한다고하면 막막할 것 같은 느낌.. 적용시키는 연습 많이 해서 하루빨리 착착 코딩을 할 수 있는 날이 왔으면 좋겠다.

 

댓글