콜백(callback)함수란?

함배·2023년 1월 28일
0

콜백 함수

콜백은 말 그대로 나중에 실행되는 코드를 의미한다.
ex) A()라는 함수가 있을 때, 인자로 어떤 함수를 넣어주었다고 하자. 자바스크립트에서 함수는 일급 객체이기 때문에 인자로 함수를 넣어주는 것이 가능.

  • 콜백 : A함수의 모든 명령을 실행한 후 마지막으로 넘겨 받은 인자 callback을 실행하는 메커니즘
  • 콜백 함수 : 여기서 인자로 들어가는 함수
    .
    .
    잘 모르겠으니 예제를 살펴보자.
    .
    .
function add(x, y){
  return x + y;
}
function printResult(result){
  console.log(result);
}
printResult(add(10,20));

위 코드를 콜백함수로 구현한다면? 다음과 같다.

function add(x, y, print){
  print(x + y);
}
function printResult(result){
  console.log(result);
}
add(10, 20, printResult);

add()함수에 콜백함수를 받을 print라는 파라미터를 추가하고,
내부에서 x+y를 인자로 전달해 준다.
그리고 print 파라미터의 인자로 printResult()함수를 전달해 주었다.
바로 여기서 printResult()함수가 콜백함수가 되는 것!!
먼저 add()함수가 호출된 후 printResult()함수가 add()함수 내부에서 나중에 호출된다.

콜백함수는 익명 함수도 인자로 전달이 가능하다.

function add(x,y, print){
  	print(x+y);
}
add(10, 20, (result) => {
	console.log(result);
})

add()함수를 실행할 때 파라미터의 인자로 새로운 함수를 지정해주었다.
(1) function(result){console.log(result)}함수가 print라는 파라미터가 되고
(2) print(x+y)자체가 함수가 되어 x+y가 result값이 되고
(3) 콘솔에 x+y를 한 result값인 30이 출력되는 것.
.
.
콜백이 유용한 이유는 하나의 함수를 여러가지로 응용할 수 있다는 것이다.

function introduce (lastName, firstName, callback) {
    var fullName = lastName + firstName;
    
    callback(fullName);
}

function say_hello (name) {
    console.log("안녕하세요 제 이름은 " + name + "입니다");
}

function say_bye (name) {
    console.log("지금까지 " + name + "이었습니다. 안녕히계세요");
}

introduce("홍", "길동", say_hello);
// 결과 -> 안녕하세요 제 이름은 홍길동입니다

introduce("홍", "길동", say_bye);
// 결과 -> 지금까지 홍길동이었습니다. 안녕히계세요

위와 같이 다른 동작을 수행하는 함수 두개를 정의해두고 introduce()함수에 인풋으로 사용하면 introduce()함수에서 받아들이는 같은 인풋을 가지고 다른 동작 수행이 가능해진다!

즉, 함수를 나눠줌으로써 코드를 재활용할 수 있고, 관리도 더 쉬워진다!!
.
.
<콜백함수 사용 원칙>

  1. 익명의 함수 사용
    함수 내부에서 실행되기 때문에 이름 붙이지 X
  1. 함수의 이름만 넘기기
function whatYourName(name, callback) {	//함수지만 callback()으로 넘기지 X
    console.log('name: ', name);
    callback();
}
function finishFunc() {
    console.log('finish function');
}
whatYourName('miniddo', finishFunc);	//함수지만 finishFunc()으로 넘기지 X
/*
name: miniddo
finish function
*/

함수를 인자로 사용할 때 callback, finishFunc처럼 ()붙일 필요 X

.
.
콜백 함수를 잘 사용하면 비동기 처리의 장점을 극대화할 수 있지만 잘못 사용하면 콜백 지옥에 빠진다는것....주의하자😂(넘 어렵)
.
.

Promise

콜백 지옥을 벗어날 수 있도록 도와줄 Promise를 배워보자!
promise는 코드의 중첩이 많아지는 콜백 지옥을 벗어날 수 있게 해주는 객체이다.

ex)'새로 출시되는 아이폰을 사고 싶은데, 출시 시간을 몰라...맨날 매시간 사이트에 접속해서 확인을 해야하니 시간도, 에너지도 낭비되네? 아이폰이 출시되었다고 알려주면 바로 아이폰을 살텐데'

  • 아이폰이 출시되었는지 계속 확인 -> 어떤 작업에 대한 요청에 비유
  • 아이폰을 구매한 행동 -> 어떤 로직이 요청에 대한 응답을 받은 후 실행한 함수를 비유
  • 애플에서 아이폰이 출시되면 문자를 보내주는 서비스를 제공할 시 이것이 -> Promise(알림을 보내준다고 약속을 하는 것과 같은 역할)!!!

Promise란
= 아이폰이 출시되면(응답이 오면) 문자를 보내주어(Promise) 바로 구매하도록(응답 후 실행할 함수) 해주는 문자 서비스!
=> 보낸 요청에 대해 응답이 준비되었을 때 알림을 주는 알리미 역할
.
.
.
[일반 비동기 함수]

function work(sec, callback){
	setTimeout(() => {
      callback(new Date().toISOString());
    }, sec*1000);
};
work(1, (result) => {
	console.log('첫 번째 작업', result);
});
work(1, (result) => {
	console.log('두 번째 작업', result);
});
work(1, (result) => {
	console.log('세 번째 작업', result);
});

첫 번째 -> 두 번째 -> 세 번째 작업 순으로 일을 하고 싶은데 위처럼 코드를 짜면 1,2,3 모두 같은 시간에 끝난 것을 알 수 있다.

[동기적 처리]

function work(sec, result){
    setTimeout(() => {
        cancelIdleCallback(new Date().toISOString());
    }, sec*1000 );
};

work(1, (result) => {
    console.log('첫 번째 작업', result);

    work(1, (result) => {
        console.log('두 번째 작업', result);

        work(1, (result) => {
            console.log('세 번째 작업', result);
        });
    });
});

[동기적 처리2]

function work(sec, callback){
    setTimeout(() => {
        callback(new Date().toISOString());
    }, sec*1000);
};

work(1, (result) => {
    console.log('첫 번째 작업', result);

    work(1, (result) => {
        work(1, (result) => {
            console.log('세 번째 작업', result);
        });
        console.log('두 번째 작업', result);
    });
});


위 두 예제의 결과는 모두 1->2->3 순으로 올바르게 작업을 할 수 있다.
.
.
하지만 이렇게 하면 눈으로 코드를 보며 로직을 바꿀 때 어떻게 해야하는지, 결과가 어떻게 될지, 확인하기 어려워짐. 이때 필요한 것이 Promise!

function workP(sec){
    //Promise의 인스턴스를 반환하고
    //then에서 반환한 것을 받는다.
    return new Promise((resolve, reject) => {
        //Promise 생성 시 넘기는 callback = resolve, reject
        //resolve 동작 완료시 호출, 오류 났을 경우 reject
        setTimeout(() => {
            resolve(new Date().toISOString());
        }, sec * 1000);
    });
}

workP(1).then((result) => {
    console.log('첫 번째 작업', result);
    return workP(1);
}).then((result) => {
    console.log('두 번째 작업', result);
});
  • workP()
    • new 키워드를 통해 Promise의 인스턴스를 생성하여 반환함.
  • Promise를 생성할 때 resolve와 reject를 넘기게 되는데, 여기서 resolve는 위에서 배운 콜백 함수와 비슷한 것이라고 생각하면 됨.
  • workP()의 요청이 성공 → resolve함수 호출
  • workP()의 요청이 실패 → reject함수 호출
  • 15행 ‘return work(1);’
    • workP()를 호출하고 반환되는 Promise의 인스턴스를 넘겨 받아 resolve를 통해 받은 결과 값을 사용할 수 있게 됨.
  • then()
    • Chainning을 해서 사용할 수 있음.
    • 이를 사용하여 callback을 순차적으로 지정해 비동기 처리를 해주게 됨.
    • 첫번째 then()에서 두번째 then()에서 받고 싶은 결과 값을 반환하고 두번째 then()에서 이를 받는다.
      • → 첫번째 then()이 반드시 끝나고 무언가를 반환해주어야 다음 then()에서 받은 결과로 무언가를 실행할 수 있으니 then()을 붙인 순서대로 처리됨.
profile
아둥바둥 개발자

0개의 댓글