비동기적으로 해야할 작업이 많아지면 코드는 자연스레 깊어지고 이는 콜백 지옥을 불러오며 이를 해결하기 위해서 프로미스를 사용한다고 언급한 바가 있습니다. 이번 포스팅은 프로미스에 대해 알아보도록 하겠습니다.
Promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다.기본적으로 promise는 함수에 콜백을 전달하는 대신에, 콜백을 첨부하는 방식의 객체입니다.
Promise는 다음 중 하나의 상태를 가집니다.
- 대기(Pending) : 이행하지도, 거부하지도 않은 초기 상태
- 이행(fulfilled) : 연산이 성공적으로 완료됨.
- 거부(rejected) : 연산이 실패함
대기 중인 프로미스는 값과 함께 이행할 수도, 어떤 이유로 인해 거부될 수도 있습니다. 이행이나 거부 될 때, 프로미스의 then 메서드에 의해 대기열(큐)에 추가된 처리기들이 호출됩니다.
주로 성공적으로 이행된 콜백 함수는 then을 통해, 실패해서 실행된 콜백함수는 catch를 통해서 error handling을 진행합니다.
비동기 함수
setTimeout은 특정 밀리초 동안 대기하고 시간이 지나면 실행하는 함수입니다. 각 2000ms, 1500ms, 1000ms 의 시간차를 두고 시간이 지나면, log를 남기는 코드를 작성하였습니다.
function log(num){
console.log(`${num} workers finished`);
}
setTimeout(log, 2000, 1)
setTimeout(log, 1500, 2)
setTimeout(log, 1000, 3)
// 3 workers finished
// 2 workers finished
// 1 workers finished
1000ms로 설정된 3번이 가장 먼저, 1500ms 인 2번이 다음, 2000ms인 1번이 마지막으로 출력된 것을 볼 수 있습니다.
이는 대표적으로 비동기 함수의 작동을 파악할 수 있는 코드입니다. 우리는 앞선 코드가 끝나기 전에 뒤에 코드가 같이 실행되어 뒤에 코드가 먼저 끝나는 모습을 볼 수 있습니다.즉 동시에 여러 작업을 수행할 수 있다는 큰 장점이 있는 것입니다.
기본적으로 웹은 서버에서 리소스를 가져오는 작업을 진행합니다. 사이트 상의 렌더링 되는 Text의 용량에 비해 Photo나 Video의 용량은 확연히 크기 때문에, Video나 Photo를 다 가져오기 전까지 화면이 그려지지 않는다면 사용자는 큰 불편함을 느낄 것입니다. 즉 이런 related to blocking 등의 이유들 때문에 웹 API의 기능은 비동기 코드를 사용하여 실행되고 있습니다.
보통 2개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황을 흔히 보게 됩니다. 그러나 비동기 함수의 수행 시간에 따라 어떤 함수가 먼저 끝날지를 모르게 되고, 기대와 *다른 값을 얻어 난처한 상황이 생깁니다.. 이를 해결하기 위해 콜백형태로 chaining을 하게 되고 결국 콜백 지옥에 빠지게 되는 것을 방지하기 위해 프로미스를 사용하는 것입니다.
(* 주로 연산을 끝낸 변수의 값을 확인하려고 console.log를 찍을 때 연산 이전 값이 출력되는 경우)
또 다른 예로 자주 사용하는 프로미스 기반 HTTP 클라이언트인 Axios의 코드를 보도록 하겠습니다.
'use strict';
import AxiosError from './AxiosError.js';
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*
* @returns {object} The response.
*/
export default function settle(resolve, reject, response) {
const validateStatus = response.config.validateStatus;
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(new AxiosError(
'Request failed with status code ' + response.status,
[AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],
response.config,
response.request,
response
));
}
}
해당 코드는 response status에 따라 resolve와 reject 콜백을 반환하는 모습을 볼 수 있습니다.
추가적인 프로미스 메소드에 대한 내용은 MDN API doc에서 확인할 수 있습니다.
[참조 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise]
[참조 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Using_promises]
[참조 : https://elvanov.com/2597]
[참조 : https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing]
'Programming Language > JavaScript' 카테고리의 다른 글
JavaScript - 이벤트 루프(Event Roop) [런타임 모델] (0) | 2022.07.13 |
---|---|
JavaScript - 가비지 컬렉션(Garbage Collection) (0) | 2022.07.08 |
JavaScript - 클로저(Closure) (0) | 2022.07.07 |
JavaScript - 변수(Variable) (0) | 2022.07.07 |
JavaScript - 콜백 함수(Callback) (0) | 2022.07.06 |