콜백 함수

Chanhee Jang·2023년 3월 28일
0

JS

목록 보기
4/9

정의

다른 코드의 인자로 넘겨주는 함수, 인자로 넘겨줌으로써 제어권도 함께 위임했다.


객체의 메소드도 콜백 함수로 전달하면 해당 객체를 this로 바라볼 수 없다.

콜백함수 내부에서 this가 객체를 바라보게 하려면 어떻게 해야될까?

  1. 별도의 인자로 this를 받는 함수일 때, 원하는 this 값을 넘겨주기
  2. 그렇지 않은 경우 this의 제어권도 넘겨주므로 아래 방법을 따른다.
    1. this를 다른 변수에 담아 콜백 함수로 활용할 함수에서는, this 대신 그 변수를 사용한다.
    2. 그리고 이를 클로저로 만든다.
var obj1 = {
  name: 'obj1',
  func: function () {
    var self = this;
    return function () {
      console.log(self.name);
    };
  }
};

var callback = obj1.func();

setTimeout(callback, 1000);

var callback2 = obj2.func();
setTimeout(callback2, 1000);

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

콜백 지옥과 비동기 제어

비동기는 동기의 반댓말이다. 동기적인 코드는 현재 실행중인 코드가 완료된 후에야 다음 코드를 실행하는 방식이다.

반대로 비동기 코드는 현재 실행중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어간다.

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, '에스프레소'); // 0.5초 간격으로 커피 리스트가 프린트 된다.

위 코드는 전형적인 콜백지옥이다.

개선 시키기 위해 익명 콜백함수에게 모두 이름을 지어주자.

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를 사용해보자.

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

개선된 Promise 코드

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를 사용한 코드

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

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

Refer - Core Javascript

profile
What is to give light must endure burning

0개의 댓글