킹의 개발일지

JavaScript - async & await 본문

프로그래밍 언어/Js

JavaScript - async & await

k1ng 2023. 3. 30. 01:00

async & await 보기전에 ‘콜백지옥’이 무엇인지, 그리고 이를 해결할 Promise를 먼저 보도록하자!

콜백 지옥

timer(1000, function() {
	console.log('어떤 일1');
	timer(1000, function() {
		console.log('어떤 일2');
		timer(1000, function() {
			console.log('어떤 일3');
		});
	});
});

위 코드는 timer를 통해서 1초후 일어날 일들을 콜백으로 처리하는 코드이다.

 

‘어떤 일 1‘이 끝나고 1초후 다시 ‘어떤일 2’가 일어나고… 이를 구현하기위해 무수히 많은 콜백을 붙힌 모습이다. 딱 봐도 실수하기 좋은 코드이지 않은가.

 

사람들을 이런 코드를 보고 ‘콜백 지옥’이라고 부른다.


Promise

이를 Promise를 사용해서 좀더 가독성이 좋은 코드로 바꿀 수 있다. 그 코드를 한 번 살펴보자.

timer(1000)
	.then(function {
		console.log('어떤 일1');
		return timer(1000);
	})
	.then(function {
		console.log('어떤 일2');
		return timer(1000);
	})
	.then(function {
		console.log('어떤 일3');
		return timer(1000);
	})

코드를 뜯어보면, timer 메서드가 Promise를 반환하고 이를 then을 사용해서 resolve해준다. 그리고 이를 체이닝해서 콜백 지옥을 맛 봤던? 코드와 동일한 기능을하는 메서드를 구현한 모습이다.

 

첫 번째 코드와 동일한 역할을 하지만 가독성이 훨씬 좋지 않은가!

하지만 이 마저 then이 반복되어서 보기 좋진 않은 모습이다. 이것을 마치 동기적으로 동작하는 메서드처럼 작성할 수 있다면 보기 더 좋지 않을까?


async & await

위에서 Promise를 통해서 설명했던 코드와 같은 동작을 하는 코드를 async와 await를 사용해서 구현해 보자.

async function run() {
	await timer(1000);
	console.log('어떤 일1');
	await timer(1000);
	console.log('어떤 일2');
	await timer(1000);
	console.log('어떤 일3');
}

// 함수 실행
run();

async와 await를 사용하니, 코드 길이부터 짧아진 것을 볼 수 있다. 뭔가 동기적인 코드처럼 보이면서 더 단순해 보이지 않은가?!

 

이 처럼 코드를 만들기 위해서는 몇가지 규칙이 있다. 이를 살펴보자.

  1. 비동기적 함수 앞에 await를 붙혀준다.
  2. await는 async 함수 안에서만 사용할 수 있다.

async와 await의 규칙과 사용 예시를 봤으니, 다음 코드의 결과가 어떻게 될지 생각해보자.

// 위 코드와 동일한 run함수
console.log('start');
run();
console.log('end');

처음 생각했을 땐 당연히 start → 어떤 일1 → 어떤 일2 → 어떤 일3 → end 라고 생각했다.

 

하지만 실제 실행시켜본다면 다음과 같은 결과를 볼 수 있다.

 

start → end → 어떤 일1 → 어떤 일2 → 어떤 일3 

 

위 같은 결과를 보면 ‘run() 이 비동기로 실행되는구나!!’ 라고 생각해볼 수 있다. 그래서 run()의 타입을 찍어보면,

 

Promise {<pending>}

 

Promise를 반환함을 알 수 있다. 즉, async 함수는 Promise를 반환하는 것이다.

 

그럼 Promise를 반환하니 이것 역시 await 키워드를 붙힐 수 있다!

 

따라서 순차적으로 실행하고 싶다면, 아래코드처럼 작성하면 된다.

async function run2() {
	console.log('start');
	await run();
	console.log('end');
}

run2();

/**
* 실행 결과
* start
* 어떤 일1
* 어떤 일2
* 어떤 일3
* end
*/

즉, async 라는 키워드는 평범한 함수를 Promise를 리턴하는 비동기적인 함수로 만들어준다.

 

그런데 만약, async 함수에 return 값이 명시적으로 존재한다면 어떻게 될까?

async function run() {
	await timer(1000);
	console.log('어떤 일1');
	await timer(1000);
	console.log('어떤 일2');
	await timer(1000);
	console.log('어떤 일3');
	return 어떤 값;
}

 

return 값이 존재한다면, return 값을 다음과 같이 변수에 저장할 수 있다.

async function run2() {
	console.log('start');
	var val = await run();
	console.log('end');
	console.log(val); // => 어떤 값 출력
}

지금까지 async & await에 대해서 살펴봤다. 자바스크립트 공부를 하며 항상 promise와 async와 await에 대한 지식이 부족하다고 느꼈는데, 좋은 공부가 되었다.

'프로그래밍 언어 > Js' 카테고리의 다른 글

Promise.all, Promise.allSettled  (0) 2023.09.11
Optional Chaining  (0) 2023.04.27
JavaScript - Promise (then, catch)  (0) 2023.03.29