자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백함수를 사용
하지만 콜백패턴은 콜벡헬로 인해 가독성이 나쁘고 처리 중 발생한 에러의 처리가 곤란하며 여러개의 비동기 처리를 한번에 처리하는데 한계가 있어 ES6에서는 비동기처리를 위한 또 다른 패턴으로 promise 도입
promise 생성자 함수는 비동기 처리를 수행할 콜백함수를 인수로 전달받는데 이 콜백함수는 resolve와 reject함수를 인수로 전달받는다.
const promise = new Promise((resolve, reject) => {
if(/*비동기 처리 성공*/){
resolve('result');
} else { /*비동기 처리 실패*/
reject('failure reason');
}
});
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.status));
}
};
});
};
promiseGet('https://jsonplaceholder.typicode.com/posts/1');
//promiseGet함수는 프로미스 반환
pending : 비동기 처리가 아직 수행되지 않은 상태 - 프로미스가 생성된 직후 기본 상태
fulfilled : 비동기 처리가 수행된 상태(성공)
→ resolve 함수 호출해 프로미스를 fulfilled 상태로 변경
rejected : 비동기 처리가 수해된 상태(실패)
→ reject 함수 호출해 프로미스를 rejected 상태로 변경
(fulfilled 또는 rejected 상태를 settled 상태라고 함)
두개의 콜백함수 인수로 전달
한개의 콜백함수 인수로 전달
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.status));
}
};
});
};
promiseGet('https://jsonplaceholder.typicode.com/posts/1')
.then(res => console.log(res))
.catch(err => console.log(err))
.finally(()=> console.log('Bye'));
비동기처리에서 발생한 에러는
하지만! then 메서드의 두번째 콜백함수는 첫번째 콜백함수에서 발생한 에러를 캐치하지 못하고 코드가 복잡해져서 가독성 좋지 않음
따라서 에러처리는 then 메서드보단 catch 매서드에서 하는 것 권장
const promiseGet = url => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.status));
}
};
});
};
const url = 'https://jsonplaceholder.typicode.com';
promiseGet(`${url}/posts/1`)
.then(({userId}) => promiseGet(`${url}/users/${userId}`))
.then(userInfo => console.log(userInfo))
.catch(err => console.error(err));
+) 프로미스도 콜백 패턴을 사용하므로 콜백함수를 사용하지 않는 것은 아님 → 가독성 떨어짐
⇒ async/await를 통해 해결 가능(후속처리 메서드 없이 동기처리처럼 프로미스가 처리 결과를 반환하도록 구현 가능)
(async () => {
const {userId} = await promiseGet(`${url}/posts/1`);
const userInfo = await promiseGet(`${url}/users/${userId}`);
console.log(userInfo);
})();
: 이미 존재하는 값을 래핑하여 프로미스를 생성하기 위해 사용
: 여러 개의 비동기 처리를 모두 병렬 처리할 때 사용
const promise1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const promise2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const promise3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));
// 세개의 비동기를 병렬로 처리
Promise.all([promise1(), promise2(), promise3()])
.then(result => {
console.log(result); // [1, 2, 3] => 약 3초보다 조금 더 소요
})
.catch(err => {
console.error(err);
})
: Promise.all 메서드와 동일하게 프로미스를 요소로 갖는 배열 등의 이터러블을 인수로 전달
const promise1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const promise2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const promise3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));
Promise.race([promise1(), promise2(), promise3()])
.then(result => {
console.log(result); // 3
})
.catch(err => {
console.error(err);
})
: 전달받은 프로미스가 모두 settled 상태가 되면 처리 결과를 배열로 반환
setTimeout(()=> console.log(1), 0);
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
따라서 이벤트 루프는 콜스택이 비면 마이크로태스크 큐 우선 실행 후 마이크로테스크 큐가 비면 태스크 큐에서 대기하고 있는 함수 실행