비동기 처리
프로그래밍 언어는 동기 적으로 동작한다. '동기적 처리'의 사전적 의미로는 '작업의 요청과 결과가 같은 시간에 발생한다'로 작업이 시작되면 작업이 끝날 때까지 해당 작업의 결과를 기다리는 것을 의미한다. 아래의 그림처럼 먼저 시작된 A가 반환된 이후 B가 실행되는 것이다. A의 수행이 오래 걸린다면 B의 시작도 늦어진다.
비동기적 처리
예를 들어 서버에서 데이터를 받아오는 등의 오래 걸리는 작업을 수행한다면 프로그램이 멈춘 것 처럼 보일 것이다. 비동기적 처리로 메인 스레드가 서버로부터 데이터를 받아올 때까지 기다리지 않고 먼저 함수를 반환하고 그 다음 작업을 수행한다. 서버에서 데이터가 수신되면 이를 처리하는 Callback이 비동기 환경에서 별도로 실행된다.
//비동기로 동작하는 함수
async function requestLogin(id, pw){
return await Fetch('http://server/login'); //서버로 로그인 요청
}
function login(inputId, inputPw){
requestLogin(inputId, inputPw).then(response=>console.log(response));
return '로그인이 요청되었습니다.';
}
function main(){
console.log(login('코딩으로세계정복', '123123'));
history.push('/home');
console.log('메인 화면으로 이동');
}
main();
//console ====================
//로그인이 요청되었습니다.
//메인 화면으로 이동
//User('코딩으로세계정복')
다음의 예시를 살펴보자. login 함수는 requestLogin 이라는 비동기 함수를 호출하고 '로그인이 요청되었습니다'를 반환한다.
main 함수는 login 함수의 반환 값을 받고 메인 화면으로 이동한다. 이 동안, requestLogin 함수는 서버로 로그인을 요청 후 기다리고 있었다. 그리고 서버로부터 로그인이 완료된 유저 데이터를 받아 반환한다. 그러면 login에서 호출한 requestLogin 뒤에 있는 then()가 비동기 함수의 응답 처리를 하게 된다.
자바스크립트의 비동기
자바스크립트는 단일 스레드로 동작하며, 비동기 환경이 별도로 존재한다. 비동기 환경은 엔진 외부에 위치하며 Event Loop, Task Queue, Job Queue 등으로 구성된다. setTimeout, Fetch 등 기본으로 제공되는 API 함수나 Promise, Async로 비동기를 사용할 수 있다.
- 비동기 처리는 우선순위가 가장 높은 JobQueue에서 작동하며, 요청 처리 후 TaskQueue에 비동기 응답을 처리하는 Callback 함수를 넣는다.
- 자바스크립트 엔진은 메인스레드의 CallStack이 비워지면 TaskQueue 내의 Callback 함수를 메인스레드에서 실행한다.
- 비동기 처리를 받지 않더라도, 모든 Callback 함수는 비동기 환경의 TaskQueue에 넣어졌다가, CallStack이 비워지면 CallStack으로 이동되어 처리된다.
Promise
const promise = new Promise((resolve, reject) => {
setTimeout( function() {
if(Math.random() > 0.5){
resolve("성공") //랜덤 값이 0.5이상인 경우 성공
}else{
reject("실패") //아니라면 실패
}
}, 250)
})
promise.then((message) => { //Then으로 성공의 경우를 응답 처리
console.log("0.5 이상이므로" + successMessage);
}).catch((message) => { //catch로 실패의 경우를 응답 처리
console.log("0.5 이하이므로" + successMessage);
}).finally() => {
console.log("Promise 종료");
};
//Promise chaining이라고 한다.
비동기 함수는 Promise를 반환한다. Promise는 비동기 작업을 진행, 성공, 실패의 상태로 표현하는 자바스크립트 객체이다. API를 개발하는 경우 주로 사용하며 함수 내부에서 resolve, reject로 비동기 동작의 상태를 값과 함께 반환할 수 있다. 함수 밖에서는 then, catch, finally로 비동기의 상태에 따른 처리를 Callback 함수와 함께 할 수 있다.
function isNotNull(value){
if(value) return Promise.resolve(true);
return Promise.reject(false);
}
isNotNull(null).then((e)=>console.log('true')).catch((e)=>console.log('false'))
//false
위와 같이 사용할 수도 있다.
Promise all
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
모든 Promise가 해결될 때까지 기다리고, 하나라도 실패 시 가장 먼저 실패한 Promise의 실패 이유를 반환한다.
Async, Await
async function requestLogin(){
try{
const data = await fetch(...); //서버에 요청하는 부분
return data;
}catch(e){
throw new Error('test');
}
}
requestLogin().then((e)=>{...}).catch((e)=>{...});
다른 비동기 함수를 함수 내부에서 사용하는 경우 위와 같이 Async-Await을 사용해 동기 코드처럼 순차적으로 표현할 수 있다. Promise를 사용하는 경우와 다른 점은 return이 resolve의 역할을 한다는 것이고 일반적으로 try-catch를 reject 대신 사용을 한다는 점이다.
마찬가지로 Promise를 반환하기 때문에 then, catch, finally로 반환 값을 처리할 수 있다.
'React > JavaScript' 카테고리의 다른 글
쓰로틀링(throttling)과 디바운싱(debouncing) (0) | 2022.06.06 |
---|---|
[JavaScript] This 포인터 이해하기 (0) | 2022.06.02 |
[JavaScript] 호이스팅과 클로저 (2) | 2022.05.06 |
[JavaScript] 실행 Context와 Scope (0) | 2022.05.06 |
[JavaScript] 자바스크립트의 구성 (0) | 2022.05.04 |