JavaScript 비동기 처리 - async, await

bp.chys·2020년 5월 20일
1
post-thumbnail

velopert님의 모던 자바스크립트 강의자료를 참고하여 작성했습니다.

async/await

async/await는 ES8에 해당하는 문법으로 Promise를 더욱 쉽게 사용할 수 있게해준다.

기본적인 사용법은 아래와 같다.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function process() {
  console.log('안녕하세요!');
  await sleep(1000); // 1초쉬고
  console.log('반갑습니다!');
}

process().then(() => {
  console.log('작업이 끝났어요!');
});

일단 함수를 선언할 때 함수 앞부분에 async키워드를 붙인다. 그리고 Promise 앞부분에 await 을 넣어주면 해당 프로미스가 끝날때 까지 기다렸다가 다음작업을 수행한다.

위 코드에서는 sleep이라는 함수를 만들어서 파라미터로 넣어준 시간만큼 기다리는 Promise를 만들고 이를 process 함수에서 사용했다.

함수에서 async를 사용하면, 해당 함수는 결과값으로 Promise를 반환하게 된다.

async함수에서 에러를 발생시킬 때는 throw를 사용하고, 에러를 잡아낼 때는 try/catch 문을 사용한다.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function makeError() {
  await sleep(1000);
  const error = new Error();
  throw error;
}

async function process() {
  try {
    await makeError();
  } catch (e) {
    console.error(e);
  }
}

process();

예제

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const getDog = async () => {
  await sleep(1000);
  return '멍멍이';
};

const getRabbit = async () => {
  await sleep(500);
  return '토끼';
};
const getTurtle = async () => {
  await sleep(3000);
  return '거북이';
};

async function process() {
  const dog = await getDog();
  console.log(dog);
  const rabbit = await getRabbit();
  console.log(rabbit);
  const turtle = await getTurtle();
  console.log(turtle);
}

process();

비동기 함수를 실행하면 프로미스함수에 전달된 시간만큼 기다렸다가 값을 반환하는데 위에서 부터 순차적으로 수행되기 때문에 총 수행시간은 4.5초가 걸린다.

만약 순차적으로 실행되는게아니라 한꺼번에 실행하고 싶다면 Promise.all을 하면된다.

async function process() {
  const results = await Promise.all([getDog(), getRabbit(), getTurtle()]);
  console.log(results);
}

//비구조화 문법을사용하면 각각의 값으로 분리해서 출력할 수 있다.
async function process() {
  const [dog, rabbit, turtle] = await Promise.all([
    getDog(),
    getRabbit(),
    getTurtle()
  ]);
  console.log(dog);
  console.log(rabbit);
  console.log(turtle);
}

Promise.all 를 사용 할 때에는, 등록한 프로미스 중 하나라도 실패하면, 모든게 실패 한 것으로 간주한다.

Promise.race

여러개의 프로미스를 등록해서 실행했을 때 가장 빨리 끝난것 하나만의 결과값을 가져온다.

async function process() {
  const first = await Promise.race([
    getDog(),
    getRabbit(),
    getTurtle()
  ]);
  console.log(first);
}

process();  // 토끼

promise 객체를 리턴하는 함수

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve();
		}, ms);
	});
}

promise 객체를 이용해서 비동기 로직을 수행할 때

p(1000).then(ms => {
	console.log(`${ms}ms 후에 실행된다.`);
});

promise 객체를 리턴하는 함수를 await로 호출하는 방법

const ms = await p(1000);
console.log(`${ms} ms 후에 실행된다.`);

위 방식은 오류가 발생한다. 그 이유는 await는 async 함수안에서만 사용이 가능하기 때문이다. await는 resolve로 넘어온 인자를 리턴한다. await의 장점은 순차실행이 직관적이라는 점이다.

(async function main() {
	const ms = await p(1000);
	console.log(`${ms} ms 후에 실행된다.`);
})();

reject 처리

try-catch를 사용해서 처리한다.

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			reject(new Error('reason');
		}, ms);
	});
}

(async function main() {
	try {
		const ms = await p(1000);
	} catch (error) {
		console.log(error);
	}
})();

async function에서 return되는 값은 Promise.resolve 함수로 감싸서 리턴된다.

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(ms);			
			//reject(new Error('reason');
		}, ms);
	});
}

async function asyncP() {
	const ms = await p(1000);
	return 'Mark: ' + ms;
}

(async function main() {
	try {
		const name = await asyncP();
		console.log(name);
	} catch (error) {
		console.log(error);
	}
})();

error의 전파 + finally

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			//resolve(ms);			
			reject(new Error('reason');
		}, ms);
	});
}

async function asyncP() {
	const ms = await p(1000);  //error 발생
	return 'Mark: ' + ms;
}

(async function main() {
	try {
		const name = await asyncP();
		console.log(name);
	} catch (error) {
		console.log(error);      //이쪽으로 넘어옴
	} finally {
		console.log('end');
})();

연속되는 promise와 async 처리

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			//resolve(ms);			
			reject(new Error('reason');
		}, ms);
	});
}

//Promise
p(1000)
	.then(() => p(1000))
	.then(() => p(1000))
	.then(() => {
		console.log('3000ms 후에 실행');
	});

//async await 더 선호되는 방식
async function process() {
	await p(1000);
	await p(1000);
	await p(1000);
	console.log('3000 ms 후에 실행');
};

process();

Promise.all과 Promise.race의 async await처리

function p(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			//resolve(ms);			
			reject(new Error('reason');
		}, ms);
	});
}

// Promise.all
(async function main() {
	const results = await Promise.all([p(1000), p(2000), p(3000)]);
	console.log(results);  //[1000, 2000, 3000]
})();

// Promise.race
(async function main() {
	const result = await Promise.race([p(1000), p(2000), p(3000)]);
	console.log(result);  //1000
})();
profile
하루에 한걸음씩, 꾸준히

0개의 댓글