본문 바로가기

공부/javascript

javascript 심화 4 (콜백함수)

반응형

 

콜백함수 📖

다른 함수가 실행이 끝난 뒤 실행되는(=callback) 함수를 말합니다! 그리고 다른 함수로 인자를 넘겨주는 함수입니다!

 

즉, 콜백 함수는 다른 함수에 인자를 넘겨줌으로써 그 제어권도 함께 위임한 함수입니다. 콜백함수를 위임받은 코드는 자체적으로 내부 로직에 의해 콜백 함수를 적절한 시점에 실행하게 됩니다.

function func(callback) {
	callback();
}
function callback() {
	console.log("callback 함수입니다.");
}

func(callback);

// 결과 : callback 함수입니다.

 

간단하게 설명하면 함수를 등록하기만 하고 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 호출하는 함수!

 

제어권 📖

1. 호출 시점

콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 `제어권`을 갖습니다.

 

아래 예시를 보시면 `setInterval`함수는 언제 콜백 함수를 호출할지에 대한 제어권을 가지게 돼서 0.3초 동안 출력되는 걸 볼 수 있습니다.

var count = 0;
var cbFunc = function () {
  console.log(count);
  if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);

// 실행 결과
// 0 (0.3sec)
// 1 (0.6sec)
// 2 (0.9sec)
// 3 (1.2sec)
// 4 (1.5sec)

 

2. 인자

콜백 함수를 넘겨받은 map 메서드는 제어권을 가지고 있기 때문에 인자의 순서까지도 제어권이 있습니다!

 

아래 코드를 보시면 첫 번째 인자로 `index` 두 번째 인자로 `currentValue`로 설정해도 map 메서드의 규칙에 맞게 호출되는 걸 확인할 수 있습니다!

// map 함수에 의해 새로운 배열을 생성해서 newArr에 담고 있네요!
var newArr2 = [10, 20, 30].map(function (index, currentValue) {
  console.log(index, currentValue);
  return currentValue + 5;
});
console.log(newArr2);

// -- 실행 결과 --
// 10 0
// 20 1
// 30 2
// [ 5, 6, 7 ]

 

3. this

제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조합니다!

// Array.prototype.map을 직접 구현해봤어요!
Array.prototype.mapaaa = function (callback, thisArg) {
  var mappedArr = [];

  for (var i = 0; i < this.length; i++) {
    // call의 첫 번째 인자는 thisArg가 존재하는 경우는 그 객체, 없으면 전역객체
    // call의 두 번째 인자는 this가 배열일 것(호출의 주체가 배열)이므로,
		// i번째 요소를 넣어서 인자로 전달
    var mappedValue = callback.call(thisArg || global, this[i]);
    mappedArr[i] = mappedValue;
  }
  return mappedArr;
};

const a = [1, 2, 3].mapaaa((item) => {
  return item * 2;
});

console.log(a);

 

제어권을 넘겨받을 코드에서 call / apply 메서드의 첫 번째 인자에서 콜백 함수 내부에서 사용될 this를 명시적으로 바인딩 하기 때문에 this에 다른 값이 담길 수 있습니다!

 

 

call / apply 가 궁금하면

 

javascript 심화 3 (this, 화살표함수, call, apply, bind)

this 📖객체지향 언어에서의 this는 클래스로 생성한 인스턴스를 말합니다. 그러나 자바스크립트에서의 this는 `자신이 속한 객체` 또는 `자신이 생성할 인스턴스`를 가리키는 자기 참조 변수입니

mingos-habitat.tistory.com

반응형

 

콜백 함수 내부에서의 this 📖

콜백 함수 내부의 this에 다른 값을 바인딩하는 방법

 

아래 코드는 내부에 `self`변수를 이용해 this를 저장해 obj1.name을 리턴하는 방식으로 사용하고 있습니다.

var obj1 = {
  name: 'obj1',
  func: function() {
    var self = this; //이 부분!
    return function () {
      console.log(self.name);
    };
  }
};

var callback = obj1.func();
setTimeout(callback, 1000);

 

그러나 단순히 함수만 전달한 것이기 때문에 obj1 객체와는 상관이 없죠.

 

 

그렇다면 콜백 함수 내부에서 this를 사용하지 않는다면

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

 

첫 번째 예제보다는 간결해졌지만 this를 하지 않아서 다양한 것을 할 수 있는 장점을 놓치고 있습니다.

 

 

그래서 this를 우회적으로 활용할 수 있는 방법에 대해서 알려드리겠습니다!

var obj1 = {
  name: 'obj1',
  func: function() {
    var self = this; //이 부분!
      return function () {
        console.log(self.name);
      };
   }
};

// 역시, obj1의 func를 직접 아래에 대입해보면 조금 더 보기 쉽습니다!
var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000);

 

첫 번째로 call 메서드를 사용하게 되면 `obj1.func`의 함수를 즉시 실행하고 `obj3`에 this를 바인딩하게 되면서 2초 뒤에 `obj3`을 출력하게 됩니다.

 

 

두 번째로 bind 메서드를 이용하는 방법도 있습니다!

var obj1 = {
  name: 'obj1',
  func: function () {
    console.log(this.name);
  }
};
//함수 자체를 obj1에 바인딩
//obj1.func를 실행할 때 무조건 this는 obj1로 고정해줘!
setTimeout(obj1.func.bind(obj1), 1000);

var obj2 = { name: 'obj2' };
//함수 자체를 obj2에 바인딩
//obj1.func를 실행할 때 무조건 this는 obj2로 고정해줘!
setTimeout(obj1.func.bind(obj2), 1500);

 

 

콜백 지옥 📖

 

말 그대로 지옥입니다. 콜백 함수 전달하는 과정이 반복되어 코드의 들여 쓰기 수준이 헬인 경우를 말합니다. 보통 비동기적인 작업을 수행할 때 발생합니다.

콜백 지옥

 

그럼 뭐가 문제일까요

유지보수 뿐만 아니라 가독성 또한 좋지 않게 됩니다.

 

이런 코드들은 비동기적인 작업을 수행할 때 발생한다고 하는데 비동기란 무엇일까요?

 

동기 vs 비동기

동기 / 비동기

 

`동기` : 현재 실행 중인 코드가 끝나야 다음 코드를 실행하는 방식입니다.

`비동기` : 실행중인 코드의 완료 여부와 상관없이 다음 코드를 실행하는 방식입니다. ex) setTimeout, addEventLisner

그래서 비동기는 동시에 여러 작업을 수행할 수 있는 장점이 있지만, 흐름을 예측하기 어렵다는 단점이 있습니다.

 

콜백 지옥 해결 방안 📖

1. 기명함수

기명함수로 변환하는 방법이 있습니다!

 

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에 대해 소개해드리려고 합니다!

 

javascript 심화 5 (Promise, async, await)

Promise란 📖Promise는 비동기 작업의 결과에 대한 상태를 나타내는 객체입니다. 아래 예시에서 new 연산자로 Promise의 인자로 넘어가는 콜백은 바로 실행됩니다. 내부에서 비동기 작업이 완료될 때

mingos-habitat.tistory.com

 

 

요약 📖

  • 콜백 함수란 다른 함수로 인자를 넘겨주는 함수, 함수를 등록하기만 하고 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 호출하는 함수!
  • 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점,  인자의 순서에 대한 제어권을 갖습니다.

 

안뇽~!😊


출처 🏷️

https://poiemaweb.com/js-async

반응형