웹 개발을 하면서 비동기는 꼭 알아야한다고 생각한다.
이런 생각이 든 이유는 지금까지 개발을 하면서 비동기 처리를 많이 했었는데 예를 들면, 게시판이 아마 대표적인 예시이지 않을까 싶다. 비동기처리는 JQuery에 Ajax로만 사용했었는데 강의를 들으면서 여러가지 비동기 처리 방법이 있다는 것을 알게 되었다.
동기와 비동기가 무엇인지 알아보자 !
console.log(1);
console.log(2);
console.log(3);
이렇게 되는 경우 1
이 출력이 되어야 다음 2
가 출력이 되고 다음 3
이 출력이 된다. 이렇게 한 동작이 끝나야 실행이 된다. 이것을 동기 라고 한다.
반면에, 비동기는
console.log(1);
setTimeout(() => {
console.log(2);
}, 2000);
console.log(3);
먼저 1
이 출력이 되고 그 다음 3
이 출력되고 2초가 지난 후 2
가 출력이 된다. 이렇게 코드 순서에 상관 없이 동작하는 것을 비동기 라고 한다.
웹을 개발한다고 하면 비동기 처리는 꼭 사용해야한다고 생각한다. 그 이유는 예를 들어 카테고리 별 상품을 보여주는 페이지를 본다고 했을 때, 내가 현재 보고 있는 카테고리 상품에서 다른 카테고리의 상품을 보기 위해 카테고리를 클릭했을 때 상품 목록만 바뀌어 화면에 보여주게 하면 된다. 하지만 비동기처리를 하지 않는다면 웹페이지를 다시 리로드를 해야 한다. 이렇게 리로드를 계속 하게 되면 자원낭비와 시간낭비를 초래한다.
const func = (callbackFunc) => {
const value = 1 + 1;
callbackFunc(value);
}
const callbackFunc = (parameter) => {
console.log(`1 + 1은 ${parameter}입니다.`);
}
func(callbackFunc);
1 + 1은 2입니다.
를 출력한다.이렇게 콜백함수를 사용할 수 있다. 하지만 콜백함수를 사용하면서 주의해야하는 점이 있다. 바로 콜백지옥이다.
콜백지옥은 콜백함수가 반복되는 것을 의미한다.
step1(function (err, value1) {
if (err) {
console.log(err);
return;
}
step2(function (err, value2) {
if (err) {
console.log(err);
return;
}
step3(function (err, value3) {
if (err) {
console.log(err);
return;
}
step4(function (err, value4) {
// ...
});
});
});
});
이렇게 콜백함수에 콜백함수에 콜백함수를 더하면 콜백지옥이 된다. 따라서, 이런 콜백지옥을 개선하기 위해 만들어진 객체가 있다. 바로 promise
이다.
promise에는 3개의 상태가 있다.
- pending = 대기 상태
- fullfill = 완료 - 성공
- reject = 완료 - 실패
let myPromise = new Promise(function(resolve, reject) {
// 성공 시 resolve()를 호출하여 결과값을 전달
// 실패 시 reject()를 호출하여 에러를 전달
});
myPromise.then(function(result) {
//결과값 활용하여 성공처리
}).catch(function(err){
// 에러 객체 활용하여 실패 처리
}).finally(function()){
// 공통 마무리 작업
})
// 화살표 함수로 작성
let myPromise = new Promise((resolve, reject) => {
// 코드 작성
});
myPromise.then((result) => {
//결과값 활용하여 성공처리
}).catch((err) => {
// 에러 객체 활용하여 실패 처리
}).finally(() => {
// 공통 마무리 작업
})
let value = 20;
let promise = new Promise((resolve, reject) => {
value > 10 ? resolve(value) : reject(value);
});
promise
.then((result) => {
console.log(result);
console.log(`${result}는 10보다 큽니다.`);
})
.catch((err) => {
console.log(`${result}는 10보다 작거나 같습니다.`);
})
.finally(() => console.log("종료"));
fetch("https://yts.lt/api/v2/list_movies.json")
.then((response) => console.log(response))
.catch((error) => console.error(error))
이렇게 promise로 콜백함수보다 더 간편하게 사용할 수 있다.
callback → promise → async / await
성공 시 resolve()로 작성해야했는데 await를 붙이면 바로 결과를 가져온다.
즉, promise로 복잡했던 구조를 더 간편하게 작성할 수 있도록 개선되었다.
Promise 코드로 비동기 처리를 했을 때는 아래 코드 처럼 작성을 했지만
const func = () => {
return new Promise((resolve, reject) => {
resolove("hello")
// or reject(new Error("error"))
});
};
func.then((result) => console.log(result));
이렇게 함수앞에 async를 붙이게 되면 promise 객체를 리턴하게 되기 때문에 코드를 더 간편하게 읽기 쉽게 작성할 수 있다.
const func = async () => {
return "hello";
}
func().then((result) => console.log(result));
예외처리 방법
promise 객체를 사용하기 때문에 .then / .catch를 사용하여 예외처리를 할 수 있다.
const func = async() => {
throw 'error';
//throw new Error("error");
//await Promise.reject(new Error("error"));
//return Promise.reject(new Error("error"));
}
func()
.then((n) => console.log(n))
.catch((n) => console.log(n));
이렇게 처리할 수 있지만 async / await는 try/catch 문
을 사용하여 예외처리를 할 수 있다.
const test = async () => {
try{
let response = await fetch("url");
}catch(error){
console.log(error)
}
}
function fetchAuthorName(postId) {
return fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`)
.then((response) => response.json())
.then((post) => post.userId)
.then((userId) => {
return fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((response) => response.json())
.then((user) => user.name);
});
}
fetchAuthorName(1).then((name) => console.log("name:", name));
const func = async (postId) => {
try {
const postResponse = await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}`
);
const post = await postResponse.json();
const userId = post.userId;
const userResponse = await fetch(
`https://jsonplaceholder.typicode.com/users/${userId}`
);
const user = await userResponse.json();
return user.name;
} catch (err) {
console.log("Fail to fetch user:", err);
return "Unknown";
}
}
func(1)
.then((name) => console.log("name:", name));
이렇게 되면 성공 했을 때는 name: name
이 출력이 되고 실패를 했을 경우 Fail to fetch user
와 name : Unknown
이 출력이 된다.