[JavaScript] 비동기 처리, 콜백 함수

SeokHun·2021년 1월 14일
0

JavaScript

목록 보기
3/3

비동기 처리

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

비동기 통신

비동기 처리의 가장 흔한 사례로 통신을 들 수 있다

const getData = () => {
	const url = '~';
	let responseData;
 	axios.get(url)
    .then((response) => {
    	responseData = response;
    });
  	console.log(responseData);
}

getData();

axios 통신을 통해 데이터를 받는 예시로서 해당 url에 HTTP GET 요청을 날려 데이터를 요청하는 코드이다

위의 코드에 따르면 서버에서 받아온 데이터는 response 인자에 담겨서 responseData에 저장되고 출력되어야 할 것이다
하지만 결과는 아래와 같이 콘솔에 데이터는 보이지 않는다

undefined

axios.get() 함수가 데이터를 요청하고 받아올 때까지 기다려주지 않고 뒤의 console.log()를 실행하기 때문이다

setTimeout

setTimeout()은 Web API의 한 종류이다
코드를 지정한 시간만큼 기다렸다가 로직을 실행하는 함수이다

console.log('first');

setTimeout(function() {
	console.log('second');
}, 3000);

console.log('third');

비동기 처리에 대한 이해가 없는 상태에서 위 코드를 보면 아래와 같은 결과를 생각할 것이다

first
second
third

하지만 실제 결과값은 아래와 같다

first
third
second

스크립트, 모듈 로딩

스크립트나 모듈을 로딩하는 것도 비동기 동작이다
아래는 스크립트를 읽어오는 함수 loadScript를 나타낸다

const loadScript = (src) => {
    let script = document.createElement('script');
    script.src = src;
    document.head.append(script);
}

loadScript('script.js');

script.js는 아래와 같은 동작을 하는 함수가 있다고 가정한다

const displayMe = () => {
    console.log("script")
}

하지만 이는 아래와 같이 함수를 찾을 수 없다는 오류가 발생한다
loadScript에서 스크립트 로딩이 완료하기도 전에 함수를 실행하려 하기 때문이다

특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것이 비동기 처리이다

콜백(callback) 함수

위에서 말한 것처럼 자바스크립트 비동기 처리 방식에 의해 생길 수 있는 문제들이 있다

이 문제들을 해결 할 때 바로 콜백 함수를 이용할 수 있다

아래 예시는 스크립트 로딩이 완료된 뒤 함수(콜백 함수)가 실행되어 무사히 함수를 실행한다

예시 (스크립트 로딩)

const loadScript = (src, callBack) => {
    let script = document.createElement('script');
    script.src = src;

    script.onload = () => callBack();

    document.head.append(script);
}

loadScript('script.js', () => {
    displayMe();
});

결과

Error Handling

콜백 함수는 에러를 핸들링 할 수 있어야 한다

오류 우선 콜백 (Error-First Callback)

오류 우선 콜백 스타일을 사용하면 단일 콜백 함수에서 에러 케이스와 성공 케이스 모두를 처리할 수 있다
콜백과 관련된 에러를 처리를 위한 일종의 코딩 약속과 같다

규칙

  • 콜백의 첫 번째 매개변수에 에러 객체를 사용한다
  • 에러가 null이나 undefined이면 정상이라고 판단한다

예시

const loadScript = (src, callback) => {
  let script = document.createElement('script');
  script.src = src;

  script.onload = () => callback(null, script);
  script.onerror = () => callback(new Error(`Error`));

  document.head.append(script);
}

loadScript('script.js', (error, script) => {
  if (error) {
    // 에러 처리
  } else {
    // 스크립트 로딩이 성공적으로 끝남
  }
});

콜백 안의 콜백

콜백 함수로 일을 처리하다 보면 중첩 호출을 해야하는 상황이 올 수 있다

아래 예시는 script 로딩을 하고난 뒤 script2 로딩을 해야할 때 실행하는 콜백 속 콜백 함수 사용 예시이다

loadScript('script.js', (script) => {
  // ~~
  loadScript('script2.js', (script) => {
    // ~~
  });
});

콜백 안에 콜백을 넣는 것은 수행하려는 동작이 단 몇 개뿐이라면 괜찮지만 동작이 많은 경우엔 좋지 않다

멸망의 피라미드, 콜백 지옥

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

콜백 지옥 코드 구조는 가독성도 떨어지고 로직을 변경하기도 어렵다
이와 같은 코드 구조를 콜백 지옥이라 한다

해결 방법

  • 함수 분리
  • Promise
  • async await

참고 사이트

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

콜백

비동기 통신

1개의 댓글

comment-user-thumbnail
2022년 9월 19일

좋은 글 잘 읽었습니다!

답글 달기