[JS] Callback 함수, Promise, async-await

황준승·2021년 9월 4일
1
post-thumbnail

콜백함수를 사용하는 이유

동기 vs 비동기에 관해서 내가 쓴 글
동기 함수의 경우 함수 호출 후 종료할 때까지 다른 작업은 수행하지 않고 기다린 다음 원래 작업을 수행한다. 그렇지만 비동기 함수 호출 후 원래 작업을 계속 수행, 즉 다른 스레드에서 함수 두 개가 동시에 수행되는 효과를 누릴 수 있다.

그렇다면 여기서 문제가 발생하는데 과연 비동기 함수 호출 후 그 함수의 리턴값을 통해 무언가 새로운 값을 도출하고 싶다면 어떻게 해야 할까??

그 답은 바로 콜백함수 이다.

Callback 함수

예제 : 3초 뒤 setTimeout 시작 출력 - 2초 뒤 다시 출력

// first
setTimeout(() => {
    console.log("setTimeout 시작");
}, 3000);

// later
setTimeout(() => {
    console.log("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
}, 2000);

아래의 결과는 다음과 같다.

나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!
setTimeout 시작

그렇다면 원래와 같은 값을 도출해내려면 어떻게 해야할까??

// first
setTimeout(() => {
    console.log("setTimeout 시작");
  	// later (콜백함수)
    setTimeout(() => {
        console.log("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
    }, 2000);
}, 2000);

다음과 같이 시작하려는 함수 안에 해당 함수를 넣으면 된다.

만약에 이러한 상황이 수십 수백 개가 있다면 어떻게 될까?? 그렇게 될 경우 코드 가독성은 매우 엉망이 되버리고 실제로 웹은 대부분의 작업들이 비동기로 이루어지기 때문에 이런 콜백 지옥에 빠져선 안된다.

Q. 그렇다면 이런 콜백지옥을 해결할 수 있는 방법은 무엇일까??

A. 바로 Promise 와 async-await이다.

Promise

정의

비동기 함수를 동기 처리하기 위해 고안한 객체입니다.
작업 결과에 따라 성공(.then) 또는 실패(.catch)를 리턴하며 결과 값을 전달 받을 수 있습니다.

Promise의 3가지 상태 및 처리 흐름

pending(대기) : 처리가 완료되지 않은 상태
fulfilled(이행) : 성공적으로 처리가 완료된 상태
rejected(거부) : 처리가 실패로 끝난 상태

State : pending -> fulfilled or rejected

// 클로저 구현을 통해 해당 함수 실행 시 text 변수와 Promise 객체를 동시에 사용하게 하기 위해서
function writeText(text){
    return new Promise((resolve, reject) => {
        setTimeout(() =>{
            resolve(text);
        },2000);
    })
}

let ThisIsText = writeText("setTimeout 시작");

ThisIsText
    .then((text) => {
        console.log(text);
        return writeText("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
    })
    .then((text) => console.log(text));

코드 설명:
내가 비동기로 실행하고 싶은 함수를 Promise로 처리한다. 이 때 Promise chain 방식을 이용하면 비동기 함수 호출 후의 동작을 다시 구현할 수 있게 된다.

Promise chain

  • 위에 코드에서 보는 것처럼 .then()함수를 통해서 Promise의 객체를 비동기로 처리하였다. 그 다음 return "[Promise 객체]"을 통해 다음 비동기 동작을 호출 할 수 있다.
// 출력
setTimeout 시작
나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!

Promise의 장점

무엇보다도 콜백지옥에서 벗어나게 해주었으며 각각의 비동기 함수에 대해 유지보수 + 가독성이 기존 콜백 지옥보다 너무나도 좋아졌다. 그리고 콜백함수의 경우 해당 콜백 함수에 대한 에러처리를 모두 적어주어야 하였는데 Promise의 경우 단 하나의 .catch로 같은 에러의 경우 하나의 구문으로 모든 처리가 가능하다.

Promise의 단점

하지만 promise객체의 단점은 .then지옥에 빠지기 쉽고 생각보다 가독성이 좋지 못하다.
따라서 이를 보완하여 나온 것이 바로 async-await이다.

async-await

위와 똑같은 예제를 async-await로 작성해보겠다.

예제

// 클로저 구현을 통해 해당 함수 실행 시 text 변수와 Promise 객체를 동시에 사용하게 하기 위해서
function writeText(text){
    return new Promise((resolve, reject) => {
        setTimeout(() =>{
            resolve(text);
        },2000);
    })
}

async function doit(){
    try{
        // console.log(foo); // 지정하지 않은 변수 출력
        console.log(await writeText("setTimeout 시작"));
        console.log(await writeText("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!"));
    } catch (err) {
        console.log("ㅇㅔ러 발생")
    }
    
}

doit();

// 나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!
// setTimeout 시작
  • 코드 설명

내가 비동기 처리를 하고 싶은 함수들을 async함수에 집어 넣고 그 함수 안에 각 비동기함수들을 동기 호출하기 위해 await를 사용한다.

이때 await 객체의 반환값으로는 우리가 지정해 주었던 Promise의 resolve함수의 인자값이다. 그래서 위의 코드에서 보는 것처럼 바로 console.log를 해주면 내가 위의 예제와 똑같이 실행되는 것을 볼 수 있다.

해당 비동기 처리에 오류 구문을 잡기 위해 try-catch구문 을 사용하여 잡을 수 있다.

더 공부해야할 내용

비동기를 공부하다보니 단순 setTimeout구문 외 ajax통신 그리고 비동기로 처리(?? 사실 개념이 모호...)하는 dom객체 에 대해 좀 더 공부하면 좋겠다라는 생각을 했다. 비동기가 처음이기도 하고 내가 짠 비동기 코드 예제로 설명하다보니 뭔가 글로 적어 설명한다는 게 너무나 어려웠다. 이는 내가 개념이 부족하다는 뜻이라 생각한다. 그래서 틈틈히 더 공부해보고 글을 고쳐나갈 생각이다.

참고자료

(callback)
[캡틴 판교] https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/
https://www.youtube.com/watch?v=U42qWURR6Gw

(promise)
[추천 : 굿굿] https://infoscis.github.io/2018/02/27/ecmascript-6-promises-and-asynchronous-programming/
https://sangminem.tistory.com/284
[mdn] https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
[캡틴 판교]https://joshua1988.github.io/web-development/javascript/promise-for-beginners/

(async-await)
[캡틴판교] https://joshua1988.github.io/web-development/javascript/js-async-await/
https://www.javatpoint.com/javascript-async-and-await
https://hangem-study.readthedocs.io/en/latest/javascript/async/

profile
다른 사람들이 이해하기 쉽게 기록하고 공유하자!!

0개의 댓글