코어 자바스크립트 스터디 4주차 - 콜백 함수

Genie·2021년 12월 9일
4

자바스크립트

목록 보기
3/4

콜백 함수란 ?

다른 코드의 인자로 넘겨주는 함수입니다. 콜백 함수를 넘겨받은 코드는 이 콜백 함수를 필요에 따라 적절한 시점에 실행할 것입니다.

callback 은 '부르다', '호출(실행)하다' 는 의미인 call 과 , '되돌아오다', '뒤돌다'는 의미인 back 의 합성어로, '되돌아 호출해달라'는 명령입니다. 어떤 함수 X를 호출하면서 '특정 조건일 때 함수 Y를 실행해서 나에게 알려달라' 는 요청을 함께 보내는 거죠. 이 요청을 받은 함수 X의 입장에서는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 Y를 직접 호출합니다.

이처럼 콜백 함수는 다른 코드(함수 또는 메서드) 에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수입니다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행할 것입니다.



제어권

  • 호출 시점 : 제어권을 넘겨받은 코드는 콜백 함수를 호출하는 시점을 스스로 판단해서 실행합니다.
  • 인자의 순서 : 콜백 함수를 호출할 때 인자로 넘겨줄 값들 및 그 순서가 정해져 있기 때문에, 이 순서를 따라서 호출해야 합니다.
  • this
    • "콜백 함수도 함수이기 때문에 기본적으로는 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다".
    • call/apply 메서드의 첫 번째 인자에 콜백 함수 내부에서의 this가 될 대상을 명시적으로 바인딩 할 수가 있다.


콜백 함수는 함수다

당연한 소리라 생각할 수 있지만, 콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출됩니다.

1) var obj = {
2)	vals: [1,2,3],
3)    logValues: function(v, i) {
4)    	console.log(this, v, i);
5)    }
6) };
7) obj.logValues(1,2);  // { vals: [1,2,3] , logValues: f }  1 2
8) [4,5,6].forEach(obj.logValues);  // Window { ... } 4 0 , Window { ... } 5 1 , Window { ... } 6 2 

7) 메서드의 이름 앞에 점이 있으니 메서드로서 호출하기 때문에, this 는 obj 를 가리킨다.
8) forEach 함수의 콜백 함수로서 전달했습니다. obj 를 this로 하는 메서드를 그대로 전달한 것이 아니라, obj.logValues가 가리키는 함수만 전달한 것입니다. 이 함수는 obj 와의 직접적인 연관이 없어집니다. forEach 에 의해 콜백이 함수로서 호출되고, 별도로 this 는 전역객체를 바라보게 됩니다.



콜백 함수 내부의 this 에 다른 값 바인딩하기

  • ES5에서 등장한 bind 메서드를 이용하는 방법을 기억하자.
var obj1 = {
	name: 'obj1',
    func: function () {
    	console.log(this.name);
    }
};
setTimeout(obj1.func.bind(obj1), 1000);

var obj2 = { name: 'obj2' };
setTimeout(obj1.func.bind(obj2), 1500);


콜백 지옥과 비동기 제어

콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상으로, 자바스크립트에서 흔히 발생하는 문제입니다.

비동기는 동기의 반대말입니다. 동기적인 코드는 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식입니다. 반대로, 비동기적인 코드는 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어갑니다.

사용자의 요청에 의해 특정 시간이 경과되기 전까지 어떤 함수의 실행을 보류한다거나(setTimeout),
사용자의 직접적인 개입이 있을 때 비로소 어떤 함수를 실행하도록 대기한다거나(addEventListener),
웹 브라우저 자체가 아닌 별도의 대상에 무언가를 요청하고, 그에 대한 응답이 왔을 때 비로소 어떤 함수를 실행하도록 대기하는(XMLHttpRequest)

위와 같은 코드는 비동기적인 코드이다.



콜백 지옥에서 벗어나려면 ...

1. 함수를 기명 함수로 변환하여 호출한다.


2. (ES6) Promise , Generator 등을 사용한다.

  • promise 는 new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행되지만 그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 다음(then) 또는 오류구문(catch) 로 넘어가지 않습니다. 따라서, 비동기 작업이 완료될 때 비로소 resolve 또는 reject 를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능합니다.

  • Generator (*이 붙은 함수가 Generator 함수) , Generator 함수를 실행하면 Iterator 가 반환되는데, Iterator 는 next 라는 메서드를 가지고 있습니다. 이 next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 부분부터 시작해서 그다음에 등장하는 yield 에서 함수의 실행을 멈춥니다. 그러니까 비동기 작업이 완료되는 시점마다 next 메서드를 호출해준다면 Generator 함수 내부의 소스가 위에서부터 아래로 순차적으로 진행된다.


3. ES2017 에서는 async / await 를 사용한다.

  • 비동기 작업을 수행하고자 하는 함수 앞에 async 를 표기하고, 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await 를 표기하는 것만으로 뒤의 내용을 Promise 로 자동 전환하고, 해당 내용이 resolve 된 이후에야 다음으로 진행합니다. 즉, Promise 의 then 과 흡사한 효과를 얻을 수 있습니다.

예시는 책을 참고



Reference

  • 코어 자바스크립트
profile
차근차근

0개의 댓글