Development/JavaScript
JavaScript 비동기 처리 방식
우봉수
2023. 9. 4. 15:28
정의: 비동기(asynchronous)
- 여러 작업이 동시에 실행되거나, 어떤 작업이 완료되기를 기다리지 않고 다음 작업을 시작하는 방식으로 주로 I/O 연산, 네트워크 요청에 유용하다.
const fs = require('fs);
console.log('start');
fs.readFile('./readme1.txt, (err, data)=>{
if(err)
console.error(err);
else
console.log('1st reading:', data.toString());
});
fs.readFile('./readme2.txt, (err, data)=>{
if(err)
console.error(err);
else
console.log('2st reading:', data.toString());
});
fs.readFile('./readme3.txt, (err, data)=>{
if(err)
console.error(err);
else
console.log('3st reading:', data.toString());
});
console.log('end');
<실행 결과>
start
end
이후 결과는 예상 불가능 동작의 순서가 cpu 스케쥴링에 따라 다르기 때문
이를 해결 하기 위한 비동기 매커니즘 방식
- 콜백 (Callback)
- promise 객체
- Async/Await 구문
콜백 (Callback)
const fs = require('fs);
console.log('start');
fs.readFile('./readme1.txt, (err, data)=>{
if(err)
console.error(err);
else{
console.log('1st reading:', data.toString());
fs.readFile('./readme2.txt, (err, data)=>{
if(err)
console.error(err);
else
console.log('2st reading:', data.toString());
fs.readFile('./readme3.txt, (err, data)=>{
if(err)
console.error(err);
else
console.log('3st reading:', data.toString());
console.log('end');
});
}
});
}
});
- 다음에 실행되어야 할 문장을 내부적으로 두면서 우선적인 작업이 완료되면 다음 작업이 실행 되도록 하는 방법
- 장점: 기본적이며 가장 원시적인 방법이기에 대부분의 자바스크립트 환경에서 지원 받을 수 있다.
- 단점: 가독성이 매우 떨어진다.
promise 객체
- 정의: 비동기 방식으로 실행하지만 아직 결과를 반환하지 않은 객체 미래에 어떤 시점에 결과를 제공하겠다는 약속을 의미함 생성시 인수로 resolve(), reject()함수를 필요로 한다.
- 성공: resolve(value)는 .then으로 연결
- 실패: rejected(value)sms .catch로 연결
const promise = new Promise( (resolve, reject) =>{
console.log('start');
fs.readFile('./readme1.txt, (err, data)=>{
if(err)
reject(err)
else
resolve(data)
})
})
promise
.then(data => {
console.log('1st reading:', data.toString());
return new Promise( (resolve, reject) =>{
fs.readFile('./readme2.txt, (err, data)=>{
if(err)
reject(err)
else
resolve(data)
});
});
})
.then(data => {
console.log('2st reading:', data.toString());
return new Promise( (resolve, reject) =>{
fs.readFile('./readme2.txt, (err, data)=>{
if(err)
reject(err)
else
resolve(data)
});
});
})
.then(data => console.log('3st reading:', data.toString()))
.catch(err => console.error(err.message);
.finally(() => console.log('end'));
- 장점: 체이닝으로 결과를 연결할 수 있어 코드의 가독성이 올라간다, 에러 처리가 개선되어 .then() 과 .catch() 메서드를 사용하여 중앙 집중식으로 에러를 처리할 수 있다.
- 단점: 여전히 .then()과 .catch()로 인해 가독성이 조금 떨어진다.
Async/Await 구문 (fs 모듈의 promises 이용)
const fs = require('fs);
const fsPromises = fs.promises;
console.log('start);
(async () => {
try {
let data = await fsPromises.readFile('./readme1.txt');
console.log('1st reading:', data.toString());
data = await fsPromises.readFile('./readme1.txt');
console.log('2st reading:', data.toString());
data = await fsPromises.readFile('./readme1.txt');
console.log('3st reading:', data.toString());
}
catch(err){
console.error(err.message);
}
finally{
console.log('end');
}
})();
- 장점: try/catch 문을 사용하여 전통적인 에러 처리 방식과 유사하게 처리함으로서 가독성이 올라가게된다.
- 단점: 오래된 브라우저에서는 지원하지 않을 가능성이 존재한다, 비동기 함수 내에서만 await 키워드를 사용이 가능하다
+fetch()
- 웹 브라우저의 API로 웹 서버로 HTTP 요청을 보내는데 사용되며, promise 객체를 반환하는 방식으로 비동기 문제를 해결한다.
- promise 객체가 resolve 응답 → then
- promise 객체가 rejected 응답 → catch
fetch(url, options).then(response => {
// 처리 로직
}).catch(error => {
// 에러 처리 로직
});