Promise는 비동기 작업을 제어하기 위해 나온 개념, CallBack Hell에서 어느정도 벗어날 수 있게 해준다. Proise로 정의된 작업끼리는 연결이 가능하며 이를 통해 코드의 깊이가 크게 증가하지 않는다.
프로미스 상태에는 3가지가 있다.
Promise 객체는 new Promise() 생성자 함수로 생성할 수 있으며 Promise 안에서는 비동기 작업이 동작한다.
const promise = new Promise((resolve, reject) => {
})
함수에는 resolve와 reject 두 개의 파라미터의 콜백함수가 주어진다. resolve, reject는 뭘까??
Promise에서는 then을 이용해 비동기 작업 성공 이후 실행할 작업을 지정한다.
then 메소드를 통해 반환된 값은 다시 promise 객체이므로 연속해서 .then 메소드를 호출하는 것이 가능하며, 이런 방식을 체이닝(chaining) 이라고 한다.
비동기 작업 후 resolve 함수가 호출되면 then이 호출된다고 생각하면 된다.
function asyncWork() {
return new Promise((resolve, reject) => {
return resolve("complete");
})
}
asyncWork()
.then(result => return asyncWork(result))
.then(result => return asyncWork(reuslt))
;
작업 중에 실패했을 경우 catch로 오류를 잡을 수 있다.
Promise 함수 내에서 비동기 작업 중 reject()가 호출되면 catch문이 호출되고 종료된다.
function asyncWork() {
return new Promise((resolve, reject) => {
return reject(new Error("error!");
})
}
asyncWork()
.then(result => {
return asyncWork(result);
}).then(result => {
return asyncWork(result);
}).catch(error => {
console.log(error)
})
성공 실패 여부와 상관없이 호출해야하는 코드가 있다면 finally에서 처리한다.
asyncWork()
.then(result => {
return asyncWork(result);
}).then(result => {
return asyncWork(result);
}).catch(error => {
console.log(error)
}).finally(() => {
console.log("무조건 실행된다")
})
비동기 작업이 여러개일 경우 Promise.all을 통해 동시에 처리가 가능하다. 여러개의 작업이 모두 끝난 시점에 then이 호출된다. 의존성이 없는 API를 호출할때 사용되기도 한다.
만약 단 하나의 Promise라도 실패 rejecte를 호출하게 된다면 모두 실패로 처리한다.
const promise1 = delay(1000);
const promise2 = delay(2000);
const promise3 = delay(3000);
Promise.all([proimse1, promise2, promise3]).then(()) => {
// 제일 긴 작업 promise3이 끝나고 실행된다.
})
Promise.race는 성공과 실패를 가리지 않고 제일 빨리 성공하거나 실패하는 Promise를 처리한다.
const promise1 = delay(1000);
const promise2 = delay(2000);
const promise3 = delay(3000);
Promise.all([proimse1, promise2, promise3]).then(()) => {
// 3개의 작업중 제일 빨리 성공하거나 실패하는 작업을 처리
})
race와 비슷하지만 성공과 실패를 가린다. 실패 작업들은 다 무시하고 가장 먼저 성공된 작업을 체크한다.
const promise1 = delay(1000);
const promise2 = delay(2000);
const promise3 = delay(3000);
Promise.all([proimse1, promise2, promise3]).then(()) => {
// 3개의 작업중 제일 빨리 성공하는 작업을 처리
})
모든 Promise 작업들이 성공했거나 실패했거나 상관없이 모두 작업이 끝난 후에 처리를 할 수 있다.
const promise1 = delay(1000);
const promise2 = delay(2000);
const promise3 = delay(3000);
Promise.all([proimse1, promise2, promise3]).then(()) => {
// 제일 긴 작업 promise3이 끝나고 실행된다.
})
then의 인자로 이미 반복되는 로직이라면 Promise함수를 통해 then을 호출하지 않아도 Promise.resolve를 호출할 때 이미 가진 데이터를 인자로 넘겨주어 바로 then의 로직을 호출할 수 있다.
const cached = {
roto: "hi"
}
const foo = (name => {
// 이미 수행한 로직의 결과라면 바로 then을 호출할 수 있다.
if(cahed[name]) {
return Promise.resolve(cached[name]);
}
// return API 요쳥...
}
강제로 reject를 발생시킬 때 사용된다.