JavaScript 비동기(1) 콜백함수, 콜백지옥

신은수·2023년 4월 26일
0

VanillaJS

목록 보기
6/11
post-thumbnail

1. 동기, 비동기

1) 동기와 비동기

  • 자바스크립트 코드는 기본적으로 순서대로 실행됨

    console.log(1);
    console.log(2);
    [3, 4, 5].forEach(i => console.log(i));
    console.log(6);
    // 1,2,3,4,5,6
  • setTimeOut, setInterval, addEventListener 와 같은 함수들은 비동기 실행 코드, 비동기란 먼저 실행된 작업이 끝날 때까지 기다리지 않고 다음 작업을 수행하는 방식. 즉, 한 번에 여러 작업을 처리함.

    console.log(1); 
    setTimeout(() => console.log(2), 100);
    [3, 4, 5].forEach(i => console.log(i));
    console.log(6);
    // 1,3,4,5,6,2

2) JavaScript는 싱글스레드라던데 비동기가 어떻게 가능한 것일까?

  • JS는 싱글 스레드가 맞다. 하지만 웹개발을 하거나 노드로 개발하는 과정에서 순수하게 JS만을 실행하는 경우는 많지 않다. 프론트엔드라면 자바스크립트 코드는 반드시 브라우저를 통해 실행되게 된다. 이 브라우저 때문에 싱글 스레드 언어인 자바스크립트가 우리 눈으로 보기엔 동시성을 갖는 작업을 해내는 것으로 보이게 된다.

  • setTimeout 예시로 자바스크립트의 비동기 처리 이해하기

    const foo = () => console.log("First");
    const bar = () => setTimeout(() => console.log("Second"), 500);
    const baz = () => console.log("Third");
    
    bar();
    foo();
    baz();

    • setTimeout 함수는 비동기 함수이기 때문에 타이머가 완료 될 때까지 콜스택에 하염없이 머물지 않고, 미래에 실행될 것을 약속한 후에 setTimeout의 콜백 함수가 Web API(비동기 API)에 추가되게 된다.

    • 콜백함수의 타이머가 완료되면 콜백함수는 태스크 큐에 들어가서 콜스택이 비워질 때까지 기다린다. 이 때, 이벤트 루프가 콜스택과 태스크 큐의 상태를 확인하며 콜스택이 비워지면 콜백 함수를 콜스택으로 이동시킨다. 이렇게 해서 콜백함수의 실행이 완료되면 콜스택을 빠져나간다.


2. 콜백함수

1) 콜백함수란?

콜백함수: 함수 타입의 값을 파라미터로 넘겨줘서, 파라미터로 받은 함수를 특정 작업이 끝나고 호출을 해주는 것을 의미한다.

function work() {
  setTimeout(() => {
    const start = Date.now();
    for (let i = 0; i < 1000000000; i++) {}
    const end = Date.now();
  	console.log(`work 작업 종료 ${end-start}ms`);
  }, 0);
}

console.log('work 작업 시작!');
work();
console.log('work 다음 작업 시작!');
// work 작업 시작! work 다음 작업 시작!, work 작업 종료 508ms

-> 만약에 work함수가 끝난 다음에 어떤 작업을 처리하고 싶다면(동기적으로 실행하고 싶다면), 아래와 같이 콜백함수를 사용

function work(callback) {
  setTimeout(() => {
    const start = Date.now();
    for (let i = 0; i < 1000000000; i++) {}
    const end = Date.now();
    console.log(`work 작업 종료 ${end-start}ms`);
    callback();
  }, 0);
}

console.log('work 작업 시작!');
work(() => {
  console.log('work 작업이 끝났어요!')
});
console.log('work 다음 작업 시작!');

// work 작업 시작! work 다음 작업 시작!, work 작업 종료 498ms, work 작업이 끝났어요!

2) 콜백지옥

콜백지옥: 비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제

function randomTime() {
  return Math.floor(Math.random() * 10) * 1000;
}

function getChicken() {
  setTimeout(() => {
    console.log('동묘시장 -> chicken');
  }, randomTime());
}

function getEgg() {
  setTimeout(() => {
    console.log(`동묘시장 -> chicken -> egg`);
  }, randomTime());
}

function getMeal() {
  setTimeout(() => {
    console.log(`동묘시장 -> chicken -> egg -> fried egg`);
  }, randomTime());
}

getChicken();
getEgg();
getMeal();

// 이런 함수가 있을 때 출력 순서를 맞추는 게 가능할까? 
//-> 위에서 배웠듯이 콜백함수를 사용하므로써 출력순서를 맞출 수 있다.
function randomTime() {
  return Math.floor(Math.random() * 10) * 1000;
}

function getChicken(callback) {
  setTimeout(() => {
    console.log('동묘시장 -> chicken');
    callback();
  }, randomTime());
}

function getEgg(callback) {
  setTimeout(() => {
    console.log('동묘시장 -> chicken -> egg');
    callback();
  }, randomTime());
}

function getMeal(callback) {
  setTimeout(() => {
    console.log('동묘시장 -> chicken -> egg -> fried egg');
    callback();
  }, randomTime());
}

getChicken(() => {
  getEgg(() => {
    getMeal(() => {});
  });
});

-> 겨우 함수 세 개일 뿐인데 해석하기 어려운 코드가 되어버렸다.
이를 깔끔하게 만들어주기 위해서 프로미스를 사용해야 한다.


참고자료
JavaScript 자바스크립트 비동기식 처리
자바스크립트에서 비동기 처리 다루기
[Javascript] 콜백지옥과 프로미스

profile
🙌꿈꾸는 프론트엔드 개발자 신은수입니당🙌

0개의 댓글