<Java Script > 비동기 통신
오늘은 자바스크립트이 비동기 작업에 대해서 알아보겠습니다.
비동기 통신이란?
대부분의 SPA 프로그램에서 서비스를 구현 할 때
(Single Page Application) -> 웹 클라이언트가 페이지에 컨텐츠를 구성할 때
서버에 다중의 페이지 요청을 해서 페이지 단위로 Response 를 받는게 아닌,
데이터만 요청해서 받은 후 하나의 페이지에서 ReRendering 하는 형태의 서비스이다,
비동기 통신이 필요한 경우
외부 API 가 Get 할 때 (외부 서버에 RESTFUL 서비스 호출 시)
파일에 접근 할 때
데이터가 큰 이미지나 컨텐츠 등을 접근해서 뿌려줄 때
비동기 통신에 필요한 객체 두가지
ES6 문법에서 제안된 비동기 통신의 수행하는 대표적인 API Promise 객체가 있고
여기서 더 진화된 Asynch & Await API 가 있다.
Promise 객체
클라이언트는 요청을 보내고 응답을 받는다.
그 응답을 분석하고 성공하면 success 실패하면 reject 를 보낸다.
그 과정에서 요청과 응답 사이에는 딜레이가 생성된다.
그 후 비동기 요청이 되어지고 xhr.onload(JsonObj) => (callback->cakkback => call) callback 지옥이 시작된다.
이걸 개선하기 위해 promise 객체가 생성되었고 특정 톨백을 수행하도록 정의한다.
실패 시에도 예외를 처리하도록 정의해야하고 methodChain 을 도입해서 다중 콜백을 처리할 수 있도록 제안된다.
Promise 객체 생성 법
const devide = (num1, num2) => {
return new Promise((resolve, reject) => {
})
}
promise 사용 안 한 예
function increaseAndPrint(n, callback) {
// 숫자 n을 파람으로 받아서 다섯번에 겹쳐 1초 후에 1씩 더해서 출력하는 로직 작성
// 1초 마다 주기적으로 수행 되어야 하기 때문에 스크립트에서 쓰레드 역할을 하는 setTimeOut 메서드 이용
setTimeout(()=>{
const incresed = n + 1;
console.log(incresed);
if(callback){
callback(incresed);
}
},1000);
}
Promise는 대표적으로 다음과 같은 3가지 상태를 가진다.
- Pending(대기): 비동기 처리 로직이 아직 미완료인 상태
- Fulfilled(이행): 비동기 처리가 완료되어 promise가 결과 값을 반환해준 상태
- Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태
메서드
- then() : promise 에서 resolve 가 리턴되어 콜백 처리를 한 후 다음 콜백을 처리할 경우에 then(calback) 을 연속으로 호출해서 처리하도록 제안한다.
- catch(): 요청이 reject 되었을 때, 처리할 예외 핸들링 메서드.
promist 사용
요청에대한 성공 실패를 리턴하는 객체 성공 시엔 resolve 를 아닌경우 reject 호출
아래 예시에서는 resolve를 사용해보겠습니다.
const myPromise =new Promise((resolve,reject)=>{
setTimout(()=>{
resolve(1);
},1000);
});
Promise 객체 메서드인 then 을 이용해보자.
myPromise.then(n=>{
console.log(n);
});
이번엔 reject를 사용해보겠습니다.
const myPromise =new Promise((resolve,reject)=>{
setTimout(()=>{
reject(new Error()); // 작업 실패
},1000);
});
myPromise.then(n=>{
console.log(n);
}).catch(error=> {
console.log(error);
});
이번에는 직접 promise 생성자를 리턴하는 로직을 짜보겠습니다.
function increaseAndPrint(n) {
//Promise 를 정의해서 성공/실패를 주도록 리턴시키고, 호출하는 로직은 then(), catch() 로 콜백 정의하도록 한다.
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const value = n + 1;
if(value ==5){
const error = new Error();
error.name = ' 5번 이상 호출';
reject(error);
return;
}
console.log(value);
resolve(value);
},1000);
});
}
pending 이 뜬 걸 확인 하면 성공적이라는 것을 볼 수 있다 .
이제 catch 를 이용해 에러까지 던지는 코드를 보여드리겠습니다.
increaseAndPrint(0).then(n=>{
return increaseAndPrint(n)
}).then(n=>{
return increaseAndPrint(n)
}).then(n=>{
return increaseAndPrint(n)
}).then(n=>{
return increaseAndPrint(n)
}).then(n=>{
return increaseAndPrint(n)
}).catch(e => {
console.log(e);
});
이렇게 작성 후 실행 하면,,
이렇게 정상적으로 실행되는 것을 볼 수 있다!
increaseAndPrint(0)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.then(increaseAndPrint)
.catch(e=>console.log(e));
이렇게 사용해도 똑같은 결과를 보여준다.
ES8 에서 제공하는 비동기통신
asych, await
기존 Promise 도 어렵고 then 의 중복 사용으로 콜백이 증가하는 걸 좀 더 쉽게 하기 위한 문법이다.
반드시 기억할 건 await 는 asynch 함수 내부에서만 호출 가능하다는 것이다.
asych , await 코드 예제
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve,ms));
}
async function proccess() {
console.log('hi');
await sleep(5000);
console.log('hello');
}
proccess() 를 호출 하면..
이렇게 실행된다.
await 는 async 에 실행이 끝날 때 까지 지정된 시간을 기다린 후 하위 로직이 돌아가게 한다
자바의 synchronized와 같은 개념인 거 같다.
이번에는 then 을 사용해보자
process()
.then(() =>{
console.log('Promise 에서 success 가 리턴되어 이 콜백을 수행');
});
then 이 실행되는 순서는 await 후 다음 수행문을 실행하고 나서 라는 것을 확인 할 수 있다.
위에서 정의한 sleep 함수를 재정의 해서 다른 예제 코드를 보여드리겠습니다.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve,ms));
};
이렇게 수정 후 아래에는 asynch 함수 객체 몇 개를 정의해서 각각 수행하도록 정의합니다.
비동기 통신을 각각 정의 해보자,
const getDog2 = async() => {
await sleep(3000);
return '왈왈';
};
const getCat = async() => {
await sleep(1000);
return '냥냥';
};
const getDuck = async() => {
await sleep(2000);
return '꽥꽥';
};
정의 후 proccess 라는 함수에 하나로 합쳐 수행해보겠습니다.
async function proccess(){
const dog =await getDog2();
console.log(dog);
const cat =await getCat();
console.log(cat);
const duck =await getDuck();
console.log(duck);
};
지정한 await 단위로 출력 되는 걸 확인 할 수 있다.
promise 의 메서드 중에 all([await 함수, 함수...]) 를 실행하면 각각 독립적으로 수행한다.
all 메서드를 이용해 위 proccess 메서드를 재정의 하겠습니다.
async function proccess(){
const result = await Promise.all([getDog2(), getCat(), getDuck()]);
console.log(result);
};
이렇게 하면 모든 쓰래드가 동시에 실행하고 (상위 쓰래드가 끝날 때 까지 대기 안 함)
모든 쓰래드가 끝나고 나서 모든 함수의 await 하위 수행문을 동시에 출력한다.
all 메서드이 단점
메서드 사용 시 비동기 결과가 하나라도 reject 이면 모두 reject 로 간주한다.
( 모든 쓰래드를 비동기적으로 한번에 수행하기 때문인 거 같다.)
다음 포스팅에서는 이것을 이용한 실습 예제를 보여드리겠습니다.
