비동기 - Callback

choi seung-i·2022년 3월 21일
0

JS로그

목록 보기
5/14
post-thumbnail

동기&비동기

기본 자바스크립트의 동작 방식 (동기)

  • Heap : 변수나 상수들에 사용되는 메모리 할당 부분
  • Call Stack : 우리가 작성한 코드에 따라 호출스택을 쌓아두는 부분
  • 스레드 : 코드를 직접 수행하는 것
    자바스크립트는 싱글스레드 방식으로 스레드 하나가 콜스택 한개만을 담당함

동기 방식

function one() {
  return 1;
}

function two() {
  return one() + 1;
}

function three() {
  return two() + 1;
}

console.log(three());

위 코드의 JS Engine 실행 순서를 봐보자

  1. 첫 Call Stack으로 Main Context 1층으로 들어옴 (프로그램 실행)
  2. Main Context 위에 실행함수 three() 가 2층에 쌓임 (대기상태)
  3. three()안에 실행함수 two()가 있어서 two() 가 3층에 쌓임 (대기상태)
  4. two()안에 실행함수 one()이 있어서 one() 이 4층에 쌓임 (대기상태)
    // -- 더이상 쌓일 코드가 없으므로 맨 위에 쌓여져있는 스택부터 실행 -- //
  5. one()함수를 실행하면 값 1을 리턴하고, one() 은 4층에서 빠져나감 (실행완료)
  6. two()함수를 실행하면 값 1+1을 리턴하고, two() 은 3층에서 빠져나감 (실행완료)
  7. three()함수를 실행하면 값 2+1을 리턴하고, three() 은 2층에서 빠져나감 (실행완료)
  8. 처음 쌓인 Main Context가 Call Stack에서 빠져나감 (프로그램 종료)

비동기 방식

기본 자바스크립트 방식에 Callback Queue가 더해짐

  • Event Loop
  • Callback Queue
  • Web APIs : 비동기실행을 위해 주어진 시간만큼 대기하는 장소
  • 다른 함수의 매개변수로 함수를 전달하고, 어떠한 이벤트가 발생한 후 매개변수로 전달한 함수가 다시 호출되는 것
  • 비동기 처리 방식의 문제점을 해결해 주기위해 사용

Callback

  • 쉽게말하면 특정 시점에서 호출이 되도록 사용하는 함수로, A함수의 인자로 대입되는 B함수를 콜백함수라고 한다.

    A가 일을 한 후에 그 결과를 가지고 B가 일을 처리해야 한다고 하면,
    자바스크립트는 A가 일을 시작한 후 B가 바로 일을 시작해버려서 B는 A의 결과를 받지 못하고 일을 한다.
    이런 상황을 막기위해 A가 일 끝날깨까지 기다렸다가 결과를 가지고 B가 일을 시작하게 하는 비동기 처리를 위한 방법


    callback함수 사용법

    function first(a, b, callback) {
        let v = a * b;
        callback(v);
    }
    
    first(1, 2, function(v) {
        console.log(v);  // 2
    })
    1. first를 호출할 때 익명함수를 parameter로 넘겨줌
    2. 1, 2, 함수 paremeter를 a, b, callback이라는 이름으로 받음
    3. 첫줄의 계산식을 한 후 v값을 callback의 parameter로 넣어주고 callback(v)실행
    4. (1*2)에 대한 결과값 콘솔에 나옴
    function first(a, b, callback) {
        let v = a * b;
        callback(v);
    }
    
    function vresult(v) {
        console.log(v);
    }
    
    first(1, 2, vresult);

    이렇게 콜백함수를 따로 빼주고 써도 동일하다.




function asyncAdd(a, b, cb) {
  setTimeout(() => {
    const res = a + b;
    cb(res);
  }, 3000);
}

asyncAdd(1, 3, (res) => {
  console.log('결과 : ', res);
})

위 코드의 JS Engine 실행 순서를 봐보자

  1. 첫 Call Stack으로 Main Context 1층으로 들어옴 (프로그램 실행)
  2. 실행함수 asyncAdd() 가 call Stack 2층에 쌓임 (대기상태)
  3. asyncAdd함수 안에는 비동기함수인 setTimeout()cb()함수를 가지고 있어서 call Stack 3층에 같이 쌓였다가 Web APIs로 넘겨져서 3000(3초)를 기다림
  4. Call Stack 에서 asyncAdd() 가 2층에서 빠져나감
  5. Web APIs에 있는 setTimeout() 이 3초가 끝나면 setTimeout() 은 제거가 되고 그 안에있는 cb()함수가 실행을 하기 위해 callbackQueue로 갔다가 Event Loop에 의해 Call Stack으로 들어가서 쌓임
  6. cb() 는 실행 후 Call Stack에서 빠져나감
  7. 처음 쌓인 Main Context가 Call Stack에서 빠져나감 (프로그램 종료)

하지만, 위 코드처럼 작성하게 될 경우 콜백 지옥을 맛볼 수 있다

taskA(4,5, (a_res) => {
  taskB(a_res, (b_res) => {
    taskC(b_res, (c_res) => {
      console.log(c_res);
    })
  })
})
// 이보다 더 길어질 수 있음을 가정하면.....

callback의 문제점

  • 비동기 처리에 콜백함수를 이용하게 되면 비동기 처리를 중첩시켜서 코드를 작성하기 때문에 에러, 예외처리가 어렵고 중첩으로 인한 복잡도가 증가.
    => 가독성 떨어지고, 유지보수가 힘듦
  • setTime()함수의 콜백은 콜백큐에 있다가 콜스택이 비어지면 실행되기 때문에 에러를 캐치하지 못한다.

그럼 어떻게?

위의 문제들을 해결하는 방법 중 하나로 Promise라는게 ES6에 나옴

Promise / async & await


공부하며 정리&기록하는 ._. 씅로그

profile
Front-end

0개의 댓글