javascript

자바스크립트 비동기 처리와 콜백함수

Bittersweet- 2022. 1. 4. 16:17
728x90

콜백함수

일반 함수가 입력(파라미터)과 출력(리턴값)있다라고 생각할 경우, 출력값이 없고 그 대신 콜백 함수를 입력받는 함수들이 있다.

콜백 함수는 다른 함수에 인자로 넘어가서 실행될 로직을 담는다.

function userInfo(id, cd) {
	const user = {
      id: id,
      name: 'User' + id,
      email: id+'@test.com',
    };
    cb(user);
  }
  
  userInfo(1, function(user) {
    console.log('user: '+user);
  });
  
  // 결과
  // user: {id:1, name:'User1', email: '1@test.com'}

userInfo() 함수의 두번째 파라미터로 콜백 함수를 선언

userInfo()가 실행될 때 cb 매개 변수는 콜백 함수를 할당받으며, cb(user); 가 실행될 때, 콜백 함수 실행

 

비동기 처리란?

특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 말함.

즉, 쉽게 말하면 호출부에서 실행한 결과를 기다리지 않아도 되는 함수임.

(반대인 동기 함수는 호출부에서 실행 결과가 리턴될 때까지 기다려야 하는 함수)

 

** 비동기 함수는 동기 함수처럼 순차적 처리가 보장되지 않기 때문에 아래에 위치한 코드가 위에 위치한 코드보다 먼저 실행될 수 있음.

 

예시1)

function getData() {
  var tableData;
  $.get('https://domain.com/products/1', function(response) {
    tableData = respons;
  });
  return tableData;
}

console.log(log(getData()); // undefined

1. $.get()는 ajax 통신을 하는 부분으로 'https://domain.com/products/1'에 HTTP GET 요청을 날려 1번 상품(product) 정보를 요청하는 코드임 (쉽게 말해서 지정된 url에 데이터를 요청하는 것과 동일)

2. 서버에서 받아온 데이터는 response 인자에 담기고, response는 tableData라는 변수에 저장됨.

3.  getData() 호출 -> undefined

 

$.get()으로 데이터를 요청한 후, 받아올 때까지 기다려주지 않고 다음 코드인 return tableData;를 실행했기 때문에 getData()의 결과 값은 초기값을 설정하지 않은 tableData의 값인 undefined로 나오는 것임.

 

예시2)

// #1
console.log('Hello');
//#2
setTimeout(function() {
  console.log('Bye');
}, 3000);
// #3
console.log('Hello Again')

결과

Hello 출력

Hello Again 출력

3초 후 Bye 출력

 

** setTimeout()은 대표적인 내장 비동기 함수로 두 개의 매개변수를 받는데, 첫번째는 실행할 작업 내용을 담은 콜백함수를, 두번째는 콜백 함수를 수행하기 전 기다리는 밀리초 단위 시간을 입력한다. 두번째 인자로 들어온 시간만큼 기다린 후에 첫번째 인자의 콜백 함수를 실행한다.

 

3초 후 다음 코드를 수행하는 것이 아니라 일단 setTimeout()을 실행하고 나서 바로 다음 코드인 console.log('Hello Again');으로 넘어가 위와 같은 결과나 나옴.

 

콜백 함수로 비동기 처리 방식의 문제점 해결

예시 1)의 코드를 콜백함수로 개선

function getData(callbackFunc) {
  $.get('https://domain.com/products/1', function() {
    callbackFunc(respons); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
  });
}

getData(function(tableData) {
  console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});

위와 같이 콜백함수를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있음.

 

콜백 지옥 (Callback hell) 해결하는 방법

$.get('url', function(response) {
  parseValue(response, function(id) {
    auth(id, function(result) {
      display(result, function(text) {
        console.log(text);
      });
    });
  });
});

* 콜백 지옥이란?

웹서비스 개발 시 서버에서 데이터를 받아와 화면에 표시하기까지 인코딩, 사용자 인증 등을 처리해야 하는 경우가 있다.

이러한 과정을 모두 비동기로 처리해야 한다고 하면 위와 코드와 같이 콜백 안에 콜백을 계속 무는 형식의 코딩을 하게 된다.

이런 코드 구조는 가독성도 떨어지고 로직 변경도 어렵다.

 

일반적으로 콜백 지옥을 해결하는 방법에는 Promise나 Async를 사용한다.

하지만 코딩 패턴만으로만 콜백 지옥을 해결하려면 아래와 같이 각각의 함수를 구분해야 한다.

function parseValueDone(id) {
  auth(id, authDone);
}
function authDone(result) {
  display(result, displayDone);
}
function displayDone(text) {
  console.log(text);
}
&.get('url', function(response) {
  parseValue(response, parseValueDone);
});

1. ajax 통신으로 받은 데이터를 parseValue() 메서드로 파싱

2. parseValueDone()에 파싱한 결과값인 id가 전달되고 auth() 메서드가 실행

3. auth() 메서드로 인증을 거치고 나면 콜백함수 authDone()이 실행

4. 인증 결과 값인 result로 display()를 호출하면 마지막으로 displayDone()메서드가 수행되면서 text 가 콘솔에 출력