콜백 함수

GY·2021년 6월 16일
0

[JS] 개념 정리

목록 보기
8/32
post-thumbnail

자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백함수를 사용한다.
콜백함수는 함수의 매개변수로 사용된 함수를 의미한다.

function add(num1, num2) {
  return num1 + num2;
}

function surprise(operator) {
  const result = operator(2, 3);
  console.log(result);
}

surprise(add);

add함수를 전달하면, add가 가리키는 함수의 주소값,
add는 add자체에 변수 공간이 할당되어서, add가 가리키는 레퍼런스가 들어있다.
surprise의 operator에는 add의 레퍼런스가 전달된다.
따라서 add를 수행하는 것과 동일하다.

함수를 바꿔가면서 인자로 전달하여 레퍼런스를 호출할 수 있으며,
함수의 인자의 이름은 임의로 정할 수 있다.


class Counter {
  constructor() {
 
    this.counter = 0;

  }

counter 클래스에는 counter라는 자체적인 변수가 있다.
counter는 클래스를 이용해 오브젝트를 만드는 순간 0으로 초기화된다.

increase(runif5times) {
   // *클래스 내부에서는 함수를 정의할 때 function을 생략할 수 있다.
   // runif5times라는 콜백함수를 만든다.
   this.counter++;
   console.log(this.counter);
   // 현재 counter클래스 내부에는 counter변수와 increase함수가 있다.
   if (this.counter % 5 === 0) {
     runif5times(this.counter);
   }
 }
}
const coolCounter = new Counter();

new 연산자를 이용해 coolCounter변수에 클래스를 이용해 오브젝트를 만든다.
new라는 키워드를 이용해 클래스를 만들면 constructor가 실행되고 변수counter가 0으로 초기화된다.

increase 함수는 runif5times로 콜백함수를 인자로 받는다.
전달된 콜백함수는 runif5times(this.counter)문에서 실행된다.

  • new 연산자를 이용해 coolCounter변수에 클래스를 이용해 오브젝트를 만든다.
  • new라는 키워드를 이용해 클래스를 만들면 constructor가 실행되고 변수counter가 0으로 초기화된다.
  • coolCounter는 0부터 시작하고, callback은 printsomething을 가리킨다.
  • increase가 호출될 때마다 수가 5배수가 되면 callback함수를 호출한다.이때,클래스 내부의 counter값을 전달한다.
  • callback은 printsomething함수를 실행시킨다.
function printsomething(num) {
  console.log(`it's ${num}`);
}
coolCounter.increase(printsomething);
coolCounter.increase(printsomething);
coolCounter.increase(printsomething);
coolCounter.increase(printsomething);
coolCounter.increase(printsomething);
coolCounter.increase(printsomething);

increase함수에 pringsomething콜백함수가 인자로 전달되어 counter를 출력한다. counter는 increase함수가 호출될 때마다 증가하기 떄문에 5의 배수가 될 때마다 printsomething이 호출되면서 it's 5와 같이 콘솔에 출력된다.

javascript is synchronous.
자바스크립트는 동기적이다.
execute the code block in order after hoisting
호이스팅이 된 이후부터 작성된 순서대로 하나씩 동기적으로 실행된다

hoisting

var,function declaration이 자동적으로 가장 우선순위로 실행이 되는 것

 console.log("1");
 setTimeout(function () {
   console.log("2");
 }, 1000);

setTimeout은 대표적은 콜백함수로, timehandler와 timeout 인자를 전달 받는다.
timeout만큼 시간이 지난뒤 timehandler함수를 실행한다.

arrow function을 사용하면 함수를 일일히 선언하지 않아도 된다.
setTimeout(() => console.log("2"), 1000);

console.log("2");
console.log("3");



synchronous callback

function printImmediately(print) {
	print();
}
printImmediately(() => console.log("hello"));

asynchronous callback

function printWithDelay(print, timeout) {
	setTimeout(print, timeout);
}
printWithDelay(() => console.log("async callback"));

브라우저 API를 사용해 우리가 원하는 print라는 콜백함수를 호출하고, timeout이라는 인자를 전달한다.

Call back hell

class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    // id와password를 받아오고,로그인이 정상적으로 이루어졌다면 onsuccess호출,실패했다면 onError콜백함수 호출
    setTimeout(() => {
      if (
        (id === "ellie" && password === "dream") ||
        (id === "coder" && password === "academy")
      ) {
        onSuccess(id);
      } else {
        onError(new Error("not found"));
      }
    }, 2000);
  }
  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === "ellie") {
        onSuccess({ name: "ellie", role: "admin" });
      } else {
        onError(new Error("no access"));
      }
    }, 1000);
  }
}

const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage.loginUser(
  id,
  password,
  (user) => {
    userStorage.getRoles(user, (userWithRole) => {
      alert("Hello ${userWithRole.name},you have a ${userWithRole.role} role");
    });
  },
  (error) => {
    console.log(error);
  }
);

콜백 안에 콜백안에 콜백 함수가 중첩되는 것이 반복되면,

  • 가독성도 떨어진다. 함수가 어떤식으로 연결되어 있는지 파악하기가 어려워진다.
  • 같은 맥락에서 디버깅을 하기 어려워 효율성이 떨어지는 코드가 될 수 있다.

ES6에서는 비동기 처리를 위한 또 다른 패턴으로 프로미스를 도입했다.
프로미스는 전통적인 콜백패턴이 가진 단점을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있다는 장점이 있다.

이 다음에는 promise에 대해 알아보자.


Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글