Promise자체의 뜻은 약속이라는 뜻입니다. 여기서 all이라는 것이 붙으면 어떤 뜻일까요?
Promise.all
Promise.all 이라는 뜻은 모든 프라미스가 이행될 때까지 기다리다 그 결과 값을 담은 배열을 반환하는 매서드입니다.
Promise란?
위 그림은 동기와 비동기에 대한 설명을 담은 그림입니다. 데이터를 요청하고 응답이 들어올 때까지 다른
task들을 처리할 수 있도록 하는 것이 바로 비동기입니다.
prmise는 위의 비유와 같이 진동벨과 같은 역할을 한다고 생각할 수 있습니다.
사장님과 손님의 진동벨을 연결하는 것과 같이, 프로미스(Promise)는 '제작 코드'와 '소비코드'를 연결해주는
특별한 자바스크립트 객체입니다.
'제작 코드'와 '소비 코드'에 대한 설명은 아래에서 코드를 보면서 설명해 보겠습니다.
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("done!"), 1000);
// executor, 제작 코드
});
promise.then(
result => alert(result);
error => alert(error);
// 소비 코드
)
위코드의 결과는 1초 후에 'done!'이 출력되는 코드 입니다. 그 이유에 대해서는 천천히 알아보도록 하겠습니다.
executor의 인수 resolve와 reject는 자바스크립트가 자체적으로 제공하는 콜백 함수 입니다.
개발자는 resolve와 reject를 신경 쓰지 않고 executor 안의 코드만 작성하면 됩니다.
대신에 executor에선 결과를 즉신 얻든, 늦게 얻든 간에 상관없이 상황에 따라 인수로 넘겨준 콜백 중 하나를
반드시 호출해야 합니다.
- resolve(value) - 일이 성공적으로 끝난 경우, 그 결과를 나타내는 value와 함께 호출
- reject(error) - 에러 발생 시 에러 객체를 나타내는 error와 함께 호출
result는 promise객체의 내부 property로 처음엔 undefined였습니다. resolve(value)가 호출되면
value로, reject(error)가 호출되면 error로 변합니다.
위 코드의 결과가 'done'이 실행되는 이유는 resolve("done")에 의해 result의 값이 resolve함수의 인수인
"done"으로 변했기 때문입니다.
위에서 언급했듯 카페 사장님과 손님의 관계를 다시 생각해보면, 제작코드(executor)는 사장님입니다.
그 사장님이 완성한 커피는 result가 되고, 그리고 그 커피를 받은 손님은 소비코드가 되는 것 입니다.
그리고 이 과정에서 커피의 완성을 알려주는 진동벨이 바로 Promise가 되는 것 입니다.
Promise.all은 언제 사용하는가?
여러개의 프로미스를 모두 리졸브가 된 후에는 , 다음 로직을 실행해야하는 경우에 사용합니다.
복수의 URL에 request를 보내고, 모든 요청의 응답이 올때 화면을 랜더 해야하는 상황이 그 예시입니다.
요청에 필요한 정보를 배열로 저장한 뒤, 그후 해당 정보를 프로미스로 매핑하여 Promise.all()에 입력하는
방법이 자주 쓰입니다.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo1');
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo2');
});
Promise.all(
[promise1, promise2, promise3, promise4]).then((values) => {
console.log(values);
});
//output: Array [3, 42, "foo1","foo2"]
처리하고자 하는 프로미스들을 배열로 담아서 Promise.all에 인자로 전달하면 배열에 있는 모든 프로미스들이
거의 동시에 트리거 됩니다. 그래서 promise3, promise4의 결과는 각각 1초가 걸리지만 동시에 트리거
되기 떄문에 2초후에 결과가 나오는 것이 아닌 1초 후에 결과가 나와야 하는 겁니다.
promise.all()을 사용할 때 주의해야할 점은 배열 내 요소 중 어느 하나라도 거부하면 즉시 거부한다는 겁니다.
let p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('하나'), 1000);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('둘'), 2000);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve('셋'), 3000);
});
let p4 = new Promise((resolve, reject) => {
setTimeout(() => resolve('넷'), 4000);
});
let p5 = new Promise((resolve, reject) => {
reject(new Error('거부'));
});
// .catch 사용:
Promise.all([p1, p2, p3, p4, p5])
.then(values => {
console.log(values);
})
.catch(error => {
console.log(error.message)
});
위 코드에서 p5가 Error를 반환하기 때문에 p1,p2,p3,p4의 결과는 출력되지 못하게 됩니다.
만약 p1,p2,p3,p4의 결과를 보고 싶다면 발생할 수 있는 거부를 사전에 처리하면 됩니다.
let p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p1_지연_이행'), 1000);
})
let p2 = new Promise((resolve, reject) => {
reject(new Error('p2 즉시 거부'));
})
Promise.all([
p1.catch(error => { return error }),
p2.catch(error => { return error }),
]).then(values => {
console.log(values[0]); // "p1_지연_이행"
console.log(values[1]); // "Error: p2_즉시 거부"
})
위 코드를 해석하면 p2에서 발생하는 거부를 .catch()를 이용해 미리 처리 하엿기 때문에 결과 배열의 p1의 결과와
p2의 error내용이 담기게 된 것입니다.
참고 자료
'프론트 엔드 > Javascript' 카테고리의 다른 글
[Javascript] 디바운싱과 쓰로틀링 (0) | 2022.02.02 |
---|---|
[Javascript] 자바스크립트 엔진, V8 (0) | 2022.01.30 |
[Javascript] Event Loop (0) | 2022.01.24 |