본문 바로가기
javascript/모던 자바스크립트

콜백함수 및 비동기, 동기 처리

by choi-dev 2024. 7. 15.

시간이 있을 때마다 모던 자바스크립트를 공부하고 더 나아가 타입스크립트를 진행하여 이를 사용하고 있는 nest.js 프레임워크까지 직접 경험해보려고 한다. 실무에서 이미 자바스크립트를 사용하고는 있는데 정확히 자바스크립트가 어떻게 구동되고 있는지 학습이 필요해보였다.

 

콜백함수

콜백함수는 다른 함수의 인자로 전달되어 그 함수 내부에서 호출되는 함수이다. 솔직히 말하면 이해를 못했다. 비동기, 동기 처리에 대한 부분을 어느 정도 이해해야 전달이 쉬운데 언어의 시작을 동기 처리로 대부분 진행되는 것을 하다보니 아무리 해도 이해가 안갔었다. 그래서 무작정 코드로 부딪혔다.

 

function taskA(callback) {
    setTimeout(() => {
        console.log('Task A completed.');
        callback();
    }, 300);
}

function taskB(callback) {
    setTimeout(() => {
        console.log('Task B completed.');
        callback();
    }, 100);
}

function taskC(callback) {
    setTimeout(() => {
        console.log('Task C completed.');
        callback();
    }, 200);
}

console.log('Starting tasks...');

taskA(() => {
    taskB(() => {
        taskC(() => {
            console.log('All tasks completed.');
        });
    });
});

console.log('Tasks have been started.');

위의 코드에 대해서 어떻게 동작하는지 설명해보라고 하면 아마 대답을 못했다. 비동기 처리만 이해하면 금방 이해하는데 그 비동기 처리를 죽어도 이해못했었다. 근데 이게 자바스크립트가 어떻게 돌아가는지 알기 시작하면서 자바와의 차이가 눈에 보이기 시작했다.

 

자바를 공부했다면 알 수 있겠지만 자바는 멀티스레드 방식이고 자바스크립트는 싱글스레드 방식이다. 그로 인해 자바는 비동기 및 동기 처리가 가능하지만 자바스크립트는 기본적으로 비동기 방식으로 처리를 한다. 그렇기 때문에 위와 같은 기이한 형태가 나타난 것이다.

 

코드로 돌아가서 저렇게 실행되면 어떻게 될지 예측할 수 있을까? 

 

Starting tasks...
Task A completed.
Task B completed.
Task C completed.
All tasks completed.
Tasks have been started.

이렇게 생각했다면 setTimeout 함수에 대해 알아보기를 바란다.

 

Starting tasks...
Tasks have been started.
Task A completed.
Task B completed.
Task C completed.

결과는 위와 같다. 어? 왜 함수 내에 콜백함수로 실행시키고 마지막에 로그 찍힌게 중간에 나온거지? 라고 생각이 들 수 있다. setTimeout 함수는 비동기 함수이다. 아직은 Promise라던가 async/await이 없기에 위의 함수들은 전부 동기로 처리되어있다. 동기로 처리되어 있는 함수에 setTimeout 같은 비동기 함수를 사용하면 이 리턴값을 자바스크립트는 기다려주질 않는다.

 

function taskA(callback) {
    setTimeout(() => {
        console.log('Task A completed.');
        callback();
    }, 300);
}

taskA 함수의 setTimeout 함수가 실행되었기에 첫번째의 로그는 잘 출력이 됐으나 다음에 해당하는 콜백을 기다리지 않고 가장 밑의 로그를 출력하고 콜백함수를 실행하게 되는 것이다.

 

Promise

Starting tasks...
Tasks have been started.
Task A completed.
Task B completed.
Task C completed.
All tasks completed.

이렇게 출력해야되면 어떻게 해야할까? 위에서 잠깐 언급했지만 Promise, async/await을 사용하면 된다.

 

function taskA() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task A completed.');
            res();
        }, 300);
    })
}

function taskB() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task B completed.');
            res();
        }, 100);
    })
}

function taskC() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task C completed.');
            res();
        }, 200);
    })
}

console.log('Starting tasks...');

const chain = taskA()
    .then(() => taskB())
    .then(() => taskC())
    .then(() => {
        console.log('All tasks completed.');
    })

console.log('Tasks have been started.');

taskA 함수가 끝날 때까지 기다리고 taskB, taskC 동일하게 동작하면 Promise로 인해 원하는대로 출력된다.

 

async/await

function taskA() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task A completed.');
            res();
        }, 300);
    })
}

function taskB() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task B completed.');
            res();
        }, 100);
    })
}

function taskC() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('Task C completed.');
            res();
        }, 200);
    })
}

console.log('Starting tasks...');

async function runTask() {
    await taskA();
    await taskB();
    await taskC();
    console.log('All tasks completed.');
}

console.log('Tasks have been started.');

runTask();

setTimeout 함수의 특성상 비동기로 await을 처리할 수 없어 Promise로 먼저 전체를 감싸주었다. 저 부분이 동기 처리를 하고 있는 것이라면 async/await으로 처리해줘도 무방하다. Promise의 사용과 크게 달라보이진 않지만 시각적으로도 훨씬 처리하기 수월해보이는 걸 알 수 있다.

 

다음 정리할 것

원래는 모던 자바스크립트를 정리한 페이지가 있어 이를 순차적으로 하려고 했으나 예전부터 콜백함수와 비동기, 동기 처리를 자꾸 헷갈려 먼저 시작했다.

 

https://ko.javascript.info/

 

모던 JavaScript 튜토리얼

 

ko.javascript.info

자바스크립트 기본이라고 하는 항목이 있는데 이 부분은 크게 다루진 않고 스스로 정독한다음 넘어갈 것이다. 조금 제대로 볼 부분은 객체: 기본이라고 하는 항목일 것이라 생각한다. 그 이유는 아무래도 객체라는 것부터 시작한 this 이런 메소드들을 제대로 정리하고 싶은 마음이 높기 때문이다.

'javascript > 모던 자바스크립트' 카테고리의 다른 글

var, let, const  (0) 2024.12.05
객체의 value 값을 다른 객체의 key 값으로 호출  (0) 2024.07.10
동기 처리와 비동기 처리  (0) 2024.03.21
비동기 처리  (0) 2024.03.13