본문 바로가기

node.js - 비동기 프로그래밍 / callback / promise / async & await 본문

개발/node.js

node.js - 비동기 프로그래밍 / callback / promise / async & await

자전하는명왕성 2023. 1. 18. 22:06

비동기적 프로그래밍

 

자바스크립트는 동기적 실행이 기본적이지만, 비동기적 실행이 필요할 때가 있다.

예를 들어, 스크립트에서 A와 B 두 가지의 API 를 요청한다고 했을 때,

두 API 끼리 상호 간 연결고리가 없다라고 한다면

A의 요청과 응답이 끝날 때까지 B를 가만히 두는 것은 시간 낭비이기 때문.

따라서 위와 같은 문제를 해소하기 위해 상호 간 응답을 기다리지 않고

코드를 진행시키는 방식을 비동기적 프로그래밍이라고 한다.

 

비동기적 프로그래밍 유형은 세 가지 정도로 볼 수 있다.

  • 콜백 함수 (callback)
  • promise (프로미스 객체)
  • ansync & await

 

콜백 함수(callback)

콜백 함수에 대해 가볍게 정의하자면, '함수에 인자로 넘겨지는 함수'라고 볼 수 있다.

예를 들면 아래와 같다.

function main(callback, data) {
	1. console.log(data)			// data
   	
   	2. callback(data) {
    	conole.log("data가 출력되었습니다.")  // "data가 출력되었습니다."
    }
    callback(data)
}
main(callback, data)

위와 같이 코드를 작성해주면, 

먼저 처리하고자 하는 1번 코드줄이 실행된 이후, 2번 코드가 실행되는 것을 확인할 수 있다.

 

콜백 지옥

특정 메서드나 명령어를 사용하지 않다보니, 구조 자체는 심플해보이나

사용함에 있어 코드가 불필요하게 길어지는 문제를 마주할 수 있는데 이를 콜백 지옥이라고 한다.

 

callback 지옥 예시

const callbackHell = () => {
                axios
                    .get(`url1`)
                    .then((res) => {
                        return axios
                            .get(`url2`)
                            .then((res)=>{
                                axios
                                .get(`url3`)
                                .then((res)=>{
				  console.log("모두 완료")
                            })
                        })
                    });
            };

 

다만, 요청과 응답을 하기 위한 get / then 로 예시를 들자면

url1 에 대한 요청과 응답, url2 에 대한 요청과 응답, url3 에 대한 응답과 요청이 줄줄이 이어져

  • 코드가 한눈에 보기에 가독성이 떨어지고
  • 어디에 문제가 생겼는지 쉽게 파악하기 힘들다.

 

promise chaining (프로미스 체이닝)

위와 같은 문제를 해결하기 위해 등장한 것이 프로미스 체이닝이다.

// 프로미스체이닝 // 실행 순서를 이해하기 어려움
const PromiseChaining = () => {
	console.log("1번째로 실행")
	axios
		.get(`url1`)
		.then((res) => {
			console.log("2번째로 실행")
			return axios.get(`url2`)
		})        
		.then((res)=>{
			console.log("3번째로 실행")
			return axios.get(`url3`)
		})
		.then((res)=>{    
			console.log("모두 완료! 4번째로 실행")
		})    
		console.log("5번째로 실행")        
};

이는 promise.then 을 사용한 경우 promise가 반환되기 때문에 사용할 수 있는 방법인데,

위 콜백 지옥에 비해 가독성이 훌륭하긴 하나 실행 순서를 이해하기 어렵다는 단점을 가진다.

예시로 위 코드의 경우, 실행 순서는 생각과 달리 1-5-2-3-4으로 이루어지는데 왜 이렇게 실행되는지에 대해서는 다음에 다뤄본다.

 

Promise (promise 객체)

Promise 는 비동기 처리를 하기 위해 사용되는 객체이다.

'성공했을 때 실행시킬 함수와 실패했을 때 실행시킬 함수를 요소로 받으며,

이를 try와 catch를 통해 상황에 따라 원하는 함수를 실행시킬 수 있다.

** 추가로 promise 객체는 then / catch 사용이 모두 가능하다.(axios 또한 promise 객체이기 때문에 가능)

new Promise((성공했을때실행시킬함수, 실패했을때실행시킬함수)=>{
  try {
  // API 요청을 한다면?
    const response = "철수" // 백엔드에서 '철수' 데이터 받아옴
    성공했을때실행시킬함수(response) // 성공하면 실행
    }catch(error){
    실패했을때실행시킬함수("실패했습니다!") // 실패하면 실행
    }})
    .then((res)=>{
      console.log(res) // 철수
    })
    .catch((err)=>{
    console.log(err) // 실패했습니다
})

 

async & await

async & await 를 이해하기 위해서는 async / await 의 역할에 대해 알아볼 필요가 있다.

async 는 function 앞에 위치하며, 해당 함수를 promise로 반환하게 한다.

await 은 async 가 덮고 있는 함수 안에서만 동작이 가능하며,

asnyc 내 promise가 처리될 때까지 기다린 후 작동하게 된다.

async & await 은 앞에서 언급한 promise.then 보다 더 심플하게 비동기적 프로그래밍을 실행할 수 있는 방법이지만,

에러가 발생한 경우 찾기 쉽지 않기 때문에, try / catch 를 사용하는 것이 좋다.

 

const myAsyncAwait = async () => {
                await axios.get(`url`);
            };
            
// then, catch 생략

2023.01.17 - [코딩/node.js] - node.js - async-await / axios 활용 문자&메일 발송 / 환경변수

위는 async-await을 활용한 방식이다.

 

 

 

Comments