[포스코x코딩온] 웹 풀스택 과정 4주차 회고 | 비동기

비동기 처리
📌 비동기 처리란?
자바스크립트는 코드를 비동기 처리하는 특성이 있다.
비동기 처리란, 앞의 코드의 연산이 끝날 때까지 기다리지 않고 바로 다음 코드를 실행하는 방식을 뜻한다.
예를 들어, 아래와 같은 코드에서 순서대로 1,2,3이 출력되는 것이 아니라, 2가 1초뒤에 출력되는 것을 기다리지 않고 3 출력 코드가 실행된다.
console.log(1);
setTimeout(function(){
console.log(2)
}, 1000);
console.log(3) // 위의 setTimeout() 코드 실행이 완료되기 전에 이미 실행됨
// 실행 결과
// 1
// 3
// 2
📌 비동기 처리하는 이유
서버로 데이터를 요청 시, 응답을 받을 때까지 다른 코드를 실행하지 않고 기다릴 수는 없기 때문이다. 동기 처리로 실행된다면, 웹 실행에 오랜 시간이 소요될 수 있다.
📌 동기 처리하는 방법
특정 코드가 완전히 실행이 끝난 후에 다음 코드가 실행되도록, 콜백함수, promise, async/awiat를 이용하여 동기 처리를 할 수 있다.
콜백함수
📌 콜백함수란?
함수의 인자(매개변수)로 대입되는 함수를 뜻한다.
응답을 받은 이후에 처리되어야 하는 종속적인 작업을 처리할 수 있다.
예를 들어, 아래의 click 이벤트 함수도 'click 이벤트가 발생했을 때' 인자로 들어온 함수(sayHello)가 실행된다.
function sayHello(){
console.log('hello~~~');
}
button.addEventListener('click',sayHello);
📌 콜백함수 사용법
함수의 인자로 넣어주면 되며, 보통 맨 마지막 파라미터로 넣어준다.
let product;
let price;
pickDrink(pay); // pay를 인자로 받음
function pickDrink(cb){ // cb로 pay가 들어옴
setTimeout(function(){
console.log("콜라를 사보자");
product = "제로 콜라";
price = 2000;
cb(product, price); // pay(product, price)가 실행됨
},3000)
}
function pay(product, price) {
console.log(`상품명: ${product}, 가격 ${price}`)
}
// 실행결과
// 콜라를 사보자
// 상품명: 제로 콜라, 가격: 2000
pickDrink(), pay() 별도의 함수로 순차적으로 코드를 작성하였다면, product, price가 정의되기 전에 pay() 함수가 실행되기 때문에, 실행 시키면 상품명과 가격이 undefined로 뜬다.
위의 예시처럼, pay()를 콜백함수로 넣어주면 product, price 값이 정의된 뒤에 pay()가 실행되도록 하여 이를 해결할 수 있다!
또한, 따로 pay()함수를 작성하지 않고, 바로 파라미터의 자리에 작성하는 방법도 있다.
pickDrink(function pay (product, price){
console.log(`상품명: ${product}, 가격: ${price}');
}) // pickDrink(pay)와 동일.
📌 콜백 지옥 (Callback Hell)
콜백함수가 반복되는 경우, 코드의 들여쓰기가 너무 깊어져 가독성이 떨어지고 코드 수정의 난이도가 높아진다.
→ Promise 객체로 해결 가능!
Promise
📌 Promise 란?
비동기 함수를 동기 처리하기 위해 만들어진 객체이다.
성공과 실패를 분리하여 반환하며, 성공한 경우 resolve(), 실패한 경우 reject() 콜백함수를 실행시킨다. (resolve, reject 명칭은 사용자가 정할 수 있음.)
📌 Promise의 상태

- Pending (대기) - Promise를 실행 중인 상태
- Fulfilled (이행) - Promise가 Resolve된 상태 (성공)
- Rejected (거부) - Promise가 Reject된 상태 (실패)
- Settled - fulfilled/rejected으로 결론이 난 상태
📌 Promise 사용법
1) Promise 객체를 반환하는 함수를 정의한다. (new로 객체 불러와야 함!)
- Promise는 두가지 콜백함수(resolve, reject)를 갖는다.
function promise1(flag){
return new Promise(function(resolve, reject)){
if (flag){
resolve('promise 상태는 fulfilled. then으로 연결됩니다. 이때의 flag는 true 입니다.')
} else {
reject('promise 상태는 rejected. catch로 연결됩니다. 이때의 flag는 false 입니다.')
}
});
}
- resolve(value): 작업이 fulfilled된 경우, 그 결과와 value를 함께 반환.
- reject(error): 작업이 rejected된 경우 (=error 발생), 그 결과와 에러 객체를 나타내는 error를 함께 반환
2) 성공/실패 시 실행할 메서드를 작성한다.
- resolve() → then 메서드 실행
- reject() → catch 메서드 실행
promise1(true).then(function(result){
console.log(result);
}).catch(function(err){
console.log(err)
})
위에서 콜백함수로만 작성했던 콜라를 구매하는 코드도 이 방법으로 동기 처리할 수 있다.
let product;
let price;
pickDrink().then(function(){
console.log(`상품명: ${product}, 가격: ${price}`)
})
// 또는 pickDrink().then(pay);
function pickDrink(){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log('콜라를 사보자');
product = '제로 콜라';
price = 2000;
resolve();
}, 3000);
})
}
function pay(){
console.log(`상품명: ${product}, 가격: ${price}`)
}
📌 Promise 체이닝
Promise 객체를 불러와 then 메서드를 연속해서 사용할 수 있는 방법으로, 콜백 지옥을 탈출할 수 있다.
→ 순차적인 작업 가능 & 간편한 예외처리 (마지막에 catch 구문으로 한번에 처리 가능하기 때문)
※ promise 객체를 불러와야, then 메서드 실행이 가능하므로, 새로운 then 메서드를 실행하기 이전에 return으로 promise(가 호출된) 함수를 가져와야 한다!
function add(n1, n2){
return new Promise(function (resolve, reject){
setTimeout(function(){
let result = n1 + n2;
resolve(result);
}, 1000)
})
}
function mul(n) {
retrun new Promise(function(resolve, reject){
setTimeout(function(){
let result = n * 2;
resolve(result);
}, 700)
})
}
add(4,3).then(function(result){
console.log("~~")
return mul(result); //
}).then(function(result){
console.log("~~~~");
}).catch(function(err){
console.log(err);
})
async/await
Promise 기반 코드를 좀 더 쉽게 읽고 쓰기 위해 등장한 최근 문법으로, Promise를 반환하고 특정 코드의 실행이 끝나도록 기다리게 해주는 역할을 한다.
async, await은 항상 같이 쓴다.
📌 async
- 함수 앞에 붙어 Promise를 반환한다. (따로 불러오는 return new 과정 없어도 됨)
- Promise가 아닌 값을 반환해도 Promise로 감싸서 반환한다.
📌 await
- Promise 앞에 붙여, 해당 Promise가 다 처리될 때까지 기다리도록 해준다.
- 비동기 처리 메서드 앞에 await을 붙이면, 다 처리될 때까지 기다려준다.
예시 - async/await으로 exec() 함수를 생성하여, 콜라를 구매하는 코드에 적용하였다.
let product;
let price;
exec();
function pickDrink(){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log('콜라를 사보자');
product = '제로 콜라';
price = 2000;
resolve();
}, 3000);
})
}
function pay(){
console.log(`상품명: ${product}, 가격: ${price}`)
}
async function exec(){
await pickDrink(); // 끝날 때까지 아래 코드가 실행되지 않고 기다린다.
pay();
}