React

ES6+ 향상된 비동기 프로그래밍(2) - 프로미스 활용

steadily 2020. 12. 4. 00:36

ES6+ 향상된 비동기 프로그래밍(2) - 프로미스 활용


ES6에서 Promise가 javascript 언어에 포함이 되었습니다.

- 이제 콜백 지옥에서 벗어나 보자. 


이전글 [React] - ES6+ 향상된 비동기 프로그래밍(1) - 프로미스




1.  프로미스 활용하기


#1 Promise(프로미스) 병렬처리: Promise.all


then 메서드로  프로미스  chain을 만들어 순차적으로 실행하기.


requestData1()
.then(data => {
console.log(data);
return requestData2();
})
.then(data => {
console.log(data);
})


병렬로 실행 되는 코드


requestData1().then(data => console.log(data));
requestData2().then(data => console.log(data));


Promise.all 사용

Promise.all([requestData1(), requestData2()])
.then( ([data1, data2]) => {
console.log(data1, data2);
});


Promise.all 함수는 프로미스를 반환한다.

입력된 모든 프로미스가 settled(처리됨) 상태가 되어야 마찬가지로 settled(처리됨) 상태가 된다.

만약 하나라도 rejected(거부됨) 상태가 된다면 Promise.all 함수가 반환하는 프로미스도 rejected(거부됨) 상태가 된다.



#2 가장 빨리 처리된 프로미스 가져오기: Promise.race


말 그대로 여러 프로미스 중 가장 빨리 settled(처리됨) 상태가 된 프로미스를 반환하는 함수다.


Promise.race를 사용한 간단한 예제


Promise.race([
requestData(),
new Promise((_, reject) => setTimeout(reject, 3000)),
])
.then(data => console.log(data))
.catch(error => console.log(error));

requestData 함수가 3초 안에 데이터를 받으면 then

그렇지 않으면 catch 메서드가 호출된다.



#3 프로미스를 이용한 데이터 캐싱


데이터를 가져오는 작업에 실패하는 경우가 고려되지 않은 간단한 예제


let cachedPromise;
function getData() {
cachedPromise = cachedPromise || requestData(); // 1
return cachedPromise;
}
getData().then(v => console.log(v));
getData().then(v => console.log(v));

1번에서 처음 호출할 때만 requestData 함수가 호출된다.



2.  프로미스 사용 시 주의사항


#1 return 키워드 깜빡하지 않기




Promise.resolve(10)
.then(data => {
console.log(data);
Promise.resolve(20); // need return
})
.then(data => {
console.log(data) // undefined
});

then 메서드 내부 함수에서 return 키워드를 입력하는 것을 깜빡하기 쉽다.



#2 Promise는 불변 객체


프로미스가 수정된다고 생각하고 작성한 코드


function requestData() {
const p = Promise.resolve(10);
p.then(() => { // 기존 객체 수정 X
return 20; // 새로운 Promise 반환
});
return p;
}

requestData().then(v => {
console.log(v) // 10
});

이제 원하는 값 20이 나오게 하려면 아래아 같이 수정해야 한다.


function requestData() {
return Promise.resolve(10).then(v => {
return 20;
});
}

requestData().then(v => {
console.log(v) // 20
});



#3 Promise를 중첩해서 사용하지 않기


콜백 패턴 만큼 복잡해지므로 지양해야 하는 중첩 코드


requestData1().then(data1 => {
requestData2(data1).then(data2 => {
//...
});
});


아래와 같이 사용하는 것이 좋다.


requestData1()
.then(data1 => {
return requestData2(data1);
})
.then(data2 => {
//...                    // 1번
});


1번 에서 data1 변수를 참조해야 한다면? 

Promise.all 함수를 사용해 중첩하지 않고 해결할 수 있다.


requestData1()
.then(data1 => {
return Promise.all([data1, requestData2(data1)]);
})
.then(([data1, data2]) => {
//...
});



#4 동기(sync) 코드 예외 처리



동기 코드에서 발행한 예외가 처리되지 않는 코드


function requestData() {
doSync(); // 동기 코드
return fetch()
.then(data => console.log(data))
.catch(error => console.log(error));
}


fetch 전에 doSync 함수가 반드시 호출되어야 하는 게 아니라면  아래와 같이 then 메서드 안쪽으로 넣어 주는 게 좋다.


function requestData() {
return fetch()
.then(data => {
doSync(); // 동기 코드
console.log(data);
})
.catch(error => console.log(error));
}

이제 catch에서는 doSync 함수에서 발생하는 예외 처리가 된다.