JavaScript

[JavaScript] 콜백함수, 비동기

하나쓰 2024. 1. 27. 08:00
728x90
반응형

콜백함수, 비동기

콜백함수

const example = (cb) => {
  setTimeout(() => {
    console.log("비동기 함수 완료");
  }, 2000);
};

console.log("비동기함수 호출");
example(() => {
  console.log("콜백함수 실행");
});
console.log("비동기 함수 호출 후 코드");

함수의 인자로 다른 함수를 전달하고 해당 함수의 실행이 끝나면 전달받은 함수를 실행하는 방식임
이를 통해 비동기적인 동작을 구현할 수 있음
하지만 콜백함수로 비동기 동작을 구현하다보면 콜백헬이 발생함

콜백헬이란?

비동기 처리 로직을 구현하기 위해 콜백 함수를 중첩하여 사용하게 되면서 발생하는 것
콜백 함수 내부에 다시 콜백 함수를 정의하고 그 안에 또 콜백 함수를 정의하는 식으로 코드가 깊게 중첩되면서 발생하는 현상
주로 이벤트 처리 및 서버 통신과 같은 비동기적 작업을 수행할 때 발생했었음

이렇게 콜백헬이 발생하면 코드를 이해하기 어려워지고 유지 보수하기에 어려워짐
따라서 비동기적인 것을 동기적으로 보이게 하는 것이 필요함
이를 위해 나온 것이 Promise, Generator(ES6), async & await(ES7)임

비동기란?

  • 동기
    현재 코드가 끝날 때까지 다음 코드를 실행하지 않는 것
  • 비동기
    실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어가는 방식
    ex: addEventListener, setTimeout 등

자바스크립트에서의 비동기 런타임 과정

여기를 참조해보자
아주 자세하게 설명되어 있음

Promise

비동기 작업의 최종 완료 또는 실패를 나타내는 객체이며, 콜백 함수로 인한 콜백헬을 해결하기 위해 도입된 개념
Promise는 pending, fulfilled, rejected의 세 가지 상태를 가지고, .then().catch() 메소드를 통해 비동기 작업의 성공, 실패를 처리할 수 있음

예시
var addCoffee = function (name) {
    return function (prevName) {
        return new Promise(function (resolve) {
            setTimeout(function () {
                var newName = prevName ? (prevName + ', ' + name) : name;
                console.log(newName);
                resolve(newName);
            }, 500);
        });
    };
};

addCoffee('에스프레소')()
    .then(addCoffee('아메리카노'))
    .then(addCoffee('카페모카'))
    .then(addCoffee('카페라떼'));
  • addCoffee는 함수를 리턴하는데, addCoffee 함수는 prevName을 인자로 받아, prevName이 있다면 prevName과 인자로 들어온 name을 합친 문자열을 리턴하고, prevName이 없다면 name을 리턴함
  • addCoffee가 반환하는 함수는 Promise를 리턴함
    이 Promise는 0.5초 뒤에 resolve되고, resolve될 때 newName이라는 변수가 Promise의 결과 값으로 전달됨
  • addCoffee 함수를 통해 만들어진 Promise는 .then() 메소드를 사용하여 then 체이닝이 됨
    addCoffee('에스프레소')()를 통해 첫 번째 Promise가 생성되고 이 Promise가 resolve되면 .then(addCoffee('아메리카노'))가 실행됨
    여기서 addCoffee('아메리카노')는 두 번째 Promise를 반환하는 함수를 리턴함
    즉, 위 코드를 실행하면

에스프레소
에스프레소, 아메리카노
에스프레소, 아메리카노, 카페모카
에스프레소, 아메리카노, 카페모카, 카페라떼

이렇게 문자열이 나오고, 이 과정이 계속 반복되어 마지막에는 '에스프레소, 아메리카노, 카페모카, 카페라떼'라는 결과 문자열이 리턴됨

async, await

ES7에 새로 도입된 비동기 처리 패턴으로 async는 함수 앞에 위치하며 해당 함수는 항상 Promise를 반환함
await는 async 함수 내부에서만 사용할 수 있으며 Promise의 처리가 끝날 때까지 기다린 후 결과를 반환함
이를 통해 비동기 처리 시간을 기다리면서도 동기적인 코드처럼 보이는 코드를 작성할 수 있음

예시
var addCoffee = function (name) {
    return new Promise(function (resolve) {
        setTimeout(function(){
            resolve(name);
        }, 500);
    });
};
var coffeeMaker = async function () {
    var coffeeList = '';
    var _addCoffee = async function (name) {
        coffeeList += (coffeeList ? ', ' : '') + await addCoffee(name);
    };
    await _addCoffee('에스프레소');
    console.log(coffeeList);
    await _addCoffee('아메리카노');
    console.log(coffeeList);
    await _addCoffee('카페모카');
    console.log(coffeeList);
    await _addCoffee('카페라떼');
    console.log(coffeeList);
};
coffeeMaker();
반응형