비동기 처리
2024.04.02 - [IT] - JavaScript / 동기/비동기
<Frontend> JavaScript / 동기/비동기
Block / NonBlock , Sync / Async 이번에는 JS에서 가장 중요하면서 어렵고 헷갈리는 개념 중 하나인 "Block / Non - Block", "Sync / Async"를 알아보겠습니다! 머리로는 이해해도 설명해보라고 하면 뭐라 설명할
rezerocodinglife.tistory.com
이전 글에서 다룬 비동기를 처리하는 방법들을 알아보겠습니다.
이번에 다룰 비동기적 코드 결과 처리 방법은 총 3가지입니다.
- Call Back
- Promise
- Async / Await (syntactic sugar)
파이팅!
1. 콜백 (Call Back)
call back은 비동기 작업의 완료 시 호출되는 함수입니다.
주로 call back 함수를 인자로 받아 비동기 작업을 수행하고, 작업이 완료되면 콜백 함수를 호출하여 결과를 처리합니다.
- 전통적인 비동기 결과 처리 방법
- 함수를 파라미터로 넘겨 파라미터를 받은 함수에게 실행권을 넘기는 것.
- call back ≠ 비동기 함수
- 특정 시점에 실행되는 함수
- 메서드를 콜백 함수로 사용하면 함수 취급.
// 동기적 콜백
const fruits = ['apple', 'banana', 'cherry']
function syncCallback(item) {
console.log(item);
}
fruits.map(syncCallback);
// 비동기적 콜백
function asyncCallback(){
console.log('Callback')
}
setTimeout(asyncCallback, 1000);
콜백 지옥(Callback Hell) / 운명의 피라미드 (Pyramid of Doom)
콜백의 단점으로는 콜백 지옥(callback hell)이 발생할 수 있다는 점입니다.
비동기 작업이 연속적으로 중첩되어 복잡한 코드가 생성되는 현상을 말합니다.
fetchData((data) => {
parseData(data, (parsed) => {
filterData(parsed, (filtered) => {
sortData(filtered, (sorted) => {
console.log(sorted); // 최종 결과 처리
});
});
});
});
- call back의 결괏값이 그다음 call back 실행에 필요한 경우
- 코드의 가독성 저하
- 유지보수성 저하
2. 프로미스 (Promise)
promise는 ES6에서 도입된 객체입니다.
비동기 작업의 성공 또는 실패와 같은 결과를 나타내는 데 사용됩니다.
promise는 비동기 작업을 수행하고, 작업이 완료되면 성공 또는 실패에 따라 처리할 수 있도록 해줍니다.
- call back + Async
- 비동기 연산을 도와주는 객체
- 생산자 - 소비자 패턴 (Producer - Customer Pattern)
const promise = new Promise((resolve, reject) => {
const isSuccess = true;
if(isSuccess){
resolve('작업 성공');
} else {
reject('작업 실패')
}
})
Promise 상태
const getUserNameById = (id) => {
if(id == 1){
return { success: true, user : {name : 'Kim'} }
}else {
return { failed: true, user : {} };
}
}
const promise = new Promise((resolve, reject) => {
const id = 1;
const result = getUserNameById(id); // pending
if(result.success) { // fulfilled
resolve(result.user);
}
if(result.failed) { // reject
reject({type : 'Not Found', message : 'id 1 is Not Found'});
}
})
promise
.then((user) => console.log(user))
.catch((error) => console.log(error))
- 대기 (pending)
- 비동기 처리 로직이 처리가 되지 않은 상황
- 성공 (fulfilled)
- 성공적으로 처리가 완료되어, Promise가 resolve를 통해 결과 값을 반환
- 실패 (rejected)
- 실패하거나 오류가 발생해 그 원인을 rejected를 통해 반환
Promise 생성
const promise = new Promise((resolve, reject) => {
// 비 동기 작업 작성
})
- new 생성자를 통해 생성
- 생성자는 실행 함수 resolve, reject를 파라미터로 받음
- resolve
- 비동기 작업이 성공적을 완료되면 호출
- 상태 값을 fulfilled 상태로 변경
- reject
- 비동기 작업이 실패했을 때 호출
- 상태 값을 rejected 상태로 변경
Promise 사용
promise
.then((result) => {
// 성공시 동작할 코드
})
.catch((error) => {
// 실패시 동작할 코드
})
.finally(() => {
// 성공 유무에 상관 없이 마지막에 실행할 코드
})
- then
- promise가 성공적으로 이행되었을 때 실행될 콜백 함수 등록
- catch
- promise가 거부되었을 때 실행 될 콜백 함수 등록
- finally
- 성공 / 실패 여부와 관계없이 마지막에 항상 실행되는 콜백
Promise Hell / Nested Promise
- call back hell에서 유래
- 여러 겹의 중첩된 Promise로 인해 가독성과 유지 보수성이 저하되는 상황
fetchData()
.then(data => {
parseData(data)
.then(parsed => {
filterData(parsed)
.then(filtered => {
sortData(filtered)
.then(sorted => {
console.log(sorted); // 최종 결과 처리
})
.catch(error => {
console.error(error); // sortData 에러 처리
});
})
.catch(error => {
console.error(error); // filterData 에러 처리
});
})
.catch(error => {
console.error(error); // parseData 에러 처리
});
})
.catch(error => {
console.error(error); // fetchData 에러 처리
});
Promise Chain
fetchData()
.then(data => parseData(data))
.then(parsed => filterData(parsed))
.then(filtered => sortData(filtered))
.then(sorted => {
console.log(sorted); // 최종 결과 처리
})
.catch(error => {
console.error(error); // 에러 처리
});
- promise를 사용하는 패턴 중 하나
- 여러 비동기 promise 작업을 순차적으로 실행하기 위해 사용
3. Async / Await
async / await은 JS에서 비동기 처리를 보다 간편하게 다룰 수 있는 "syntactic sugar"입니다.
async / await은 Promise를 기반으로 하며, 내부적으로는 Promise를 사용하여 비동기 작업을 처리합니다.
const asyncFuncfion = async() => {...}
const value1 = await asyncFunction();
const value2 = await asyncFunction();
const value3 = await asyncFunction();
- async 함수
- 함수 앞에 async 키워드를 사용하여 정의
- 함수는 항상 Promise를 반환
- 함수 내부에서 await 키워드 사용가능
- await 표현식
- Promise 앞에서 사용
- 해당 Promise가 처리될 때까지 async 함수의 실행을 일시 중지시킴
// Promise
const greetPromise = () => {
return new Promise((resolve, reject) => {
resolve('hello')
})
}
// Async 형태. 기본적으로 Promise를 리턴.
const greetAsync = async() => {
return 'hello'
}
Async / Await 예외 처리 방식
- try - catch 문법 사용
const greet = async () => {
const isSuccess = true;
if(isSuccess){
return 'Hello'
}else {
throw 'Bye'
}
}
try{
const greetText = await greet();
console.log(greetText); // hello
}catch(e){
console.log(e); // Bye
}
비동기 처리 Callback, Promise 기반
Callback 기반 비동기 처리 방식
AJAX (Asynchronuous JavaScript And XML)
- 자체 빌트인 함수인 XMLHttpRequest를 사용
- 사용하기에는 너무 복잡한 원시적인 코드
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
} else {
console.error(xhr.responseText);
}
}
};
xhr.open('GET', 'http://localhost');
xhr.send();
jQuery AJAX
- 크로스 브라우저 환경에서 일관된 자바스크립트 문법 제공을 위한 라이브러리
- DOM, CSS 조작이 매우 간편해지고 기능이 매우 다양
- AJAX 만을 사용하기 위해서 쓰기에는 너무 거대.
- 사용 시에는 분명한 목적이 있어야 함.
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function (res) { console.log(res); },
error: function (res) {console.log(res); }
});
Promise 기반
Fetch API
- ES6 지원 비동기 통신을 위한 JS 내장 API
- 라이브러리가 아니기 때문에 매우 가볍게 동작 가능
try {
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
Axios
- 서드파티 라이브러리
- 자동으로 JSON 변환 과정이 포함되어 있어 편리
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
'Frontend' 카테고리의 다른 글
<Frontend> JavaScript / 동기/비동기 (0) | 2024.04.02 |
---|---|
<Frontend> JavaScript / 모듈 시스템 (Module) (0) | 2024.03.27 |
<Frontend> JavaScript / This (0) | 2024.03.27 |
<Frontend> JavaScript / 객체(Object) (0) | 2024.03.26 |
<Frontend> JavaScript / 실행 컨텍스트 (0) | 2024.03.26 |