특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드들을 수행하는 것 자바스크립트는 싱글 스레드 프로그래밍 언어이기 때문에 비동기 처리가 필수적이다.
비동기 처리는 그 결과가 언제 반환될지 알수 없기 때문에 동기식으로 처리하는 기법들이 사용되어야 하는데, 대표적으로
setTimeout
이 있고callback
과promise
가 있다.
async/await
를 사용하면 비동기 처리를 좀 더 간단히 구현할 수 있다.function foo() {
return new Promise((resolve, reject) => {
resolve('hello');
// or reject(new Error('error');
});
}
foo().then((e) => console.log(e));
async function foo2(){ // async을 지정해주면 Promise를 리턴하는 함수가 된다.
return 'hello_2'; //리턴값은 Promise{<resolved>: "hello2"} 자동 resolve해준다는걸 알 수있다.
// reject는 throw 에러를 보낸다.
}
foo2().then((e) => console.log(e));
함수에 async만 붙이면 자동 Promise객체로 인식되고 return값은 resolve()
값과 똑같다.
리턴값은 Promise{<resolved>: "hello_2"}
문자열이 리턴되는것이 아님
다음과 동일한 함수
async function foo(){ // async을 지정해주면 Promise를 리턴하는 함수와 같다.
//return 'hello2';
return Promise.resolve('hello'); // 똑같다
}
function 키워드 앞에 async
만 붙여준다.
비동기로 처리되는 부분 앞에 await
만 붙여준다.
async
가 붙은 함수는 Promise
를 반환하고, Promise가 아니면 Promise로 감싸 반환한다.
await
키워드를 만나면 Promise가 처리(settled)될 때까지 기다린다. --> 처리가 완료되어 resolve(값) 되면 값만 따로 추출해서 리턴
await는 promise.then
보다 가독성 좋고 쓰기도 쉽다.
async function foo() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Resolved"), 1000)
});
let result = await promise; // then방식에서는, promise.then(()=>{})을 통해 비동기를 받아야하지만
// await 키워드로 직관적 으로 볼 수 있다.
alert(result); // "완료!"
}
foo();
❖
async/await
가Promise
를 대체하지는 않는다.
비동기는 Promise객체로 처리하고
async/await는 비동기를 동기식으로 처리하는 기법이다.
기존에는 Promise에 직접.then()
을 통해 동기처리를 했지만,
await
를 사용하면 바로 동기처리가 되기 떄문이다.
function num1(){
return new Promise( (resolve, reject) => {
setTimeout(() => resolve("num1"), 100);
})
}
function num2(){
return new Promise( (resolve, reject) => {
setTimeout(() => resolve("num2"), 100);
})
}
function Number(){
num1()
.then((n1) => { // 리턴값 === resolve()니까 then 가능
num2()
.then((n2) => console.log(`${n1} and ${n2}`));
}) // 콜백지옥
}
Number() // 결과 : num1 and num2
프로미스로 비동기 함수를 만들고, 동기 처리를 async
로 하면 된다.
delay()
라는 프로미스 객체 비동기 함수를 만들고,
각 async함수
num1, num2 동기처리를 한다.
function delay(){
return new Promise( (resolve, reject) => {
setTimeout(() => resolve(), 1000);
})
}
async function num1(){
await delay();
return "num1";
}
async function num2(){
await delay();
return "num2";
}
function Number(){
num1()
.then((n1) => { // 리턴값 === resolve()니까 then 가능
num2()
.then((n2) => console.log(`${n1} and ${n2}`));
}) // 콜백지옥
}
Number(); // 결과 : num1 and num2
위의 코드에서 async
에서 리턴한 값(Promise.resolve(값))
을 then
으로 처리할 필요는 없다.
resolve의 값을 추출해 변수에 할당하면 외부함수에서 처리할 수 있다.
function delay(){
return new Promise( (resolve, reject) => {
setTimeout(() => resolve(), 1000);
})
}
async function num1(){
await delay();
return "num1";
}
async function num2(){
await delay();
return "num2";
}
async function Number(){
let a = await num1(); //리턴값이 resolve()의 값이니까 대입 가능
let b = await num2();
console.log(`${a} and ${b}`);
}
Number(); // 결과 : num1 and num2
다음과 같이 a``b
사이의 딜레이를 없애고 병렬 처리할 수 있다.
async function Number(){
let getnum1 = num1(); // async함수를 실행시킨다. 논블록킹으로 백단에서 실행되게 된다.
let getnum2 = num2(); // 리턴으로 프로미스 객체로 감싸진 결과값을 받는다.
let a = await getnum1; // 리턴으로 받은 프로미스객체를 done(data)를 await으로 빼서 변수에 넣음
let b = await getnum2;
// 본래라면 1초+1초 를 기다려야 하는데, 위에서 1초기다리는 함수를 한번에 불러왔기 때문에, 대충 1.001초만 기다리면 동기식으로 처리된다.
console.log(`${a} and ${b}`);
}
(Promise의 reject()
를 async에서 구현)
try.. catch
-> throw
리턴값이 Promise객체이니 잡는 방법도 Promise.catch()
방법과 같다.
async function p2(){
throw 'error';
//throw new Error("error");
//await Promise.reject(new Error("error"));
//return Promise.reject(new Error("error"));
}
p2()
.then((n) => console.log(n))
.catch((n) => console.log(n));
function p(){
return new Promise((resolve, reject) => {
reject("Error!!");
},1000)
}
(async function p2(){
try{
await p(); // Promise에서 reject가 될때까지 await한다.
}catch(e){
console.error(e);
}
})();