프로미스 처리 흐름 (출처 MDN)
const promise = new Promise()
const promise = new Promise(function () {
// something..
});
resolve
와 reject
는 함수이다. const promise = new Promise(function (resolve, reject) {
// do something async here
});
프러미스 생성자 함수에 인자로 들어간 함수 내부에서 우리는 비동기 작업을 하고, 비동기 작업이 성공할 경우 resolve를 실행해야 하고, 실패할 경우 reject를 실행해야 한다.
const promise = new Promise(function (resolve, reject) {
// do something async here..
fs.readFile(path, "utf-8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
위와 같이 생성한 프로미스 객체는 미래에 맞이할 성공 혹은 실패에 대한 결과값을 나타낸다. 미래에 결과를 돌려주겠다는 약속이다. 모든 프러미스 객체는 다음 세 가지 상태 중 하나의 상태를 가지며, 한번이라도 성공하거나 실패한 프러미스는 초기 상태로 돌아갈 수 없다.
프러미스 인스턴스는 .then
, .catch
등의 메소드를 사용할 수 있다.
위 메소드는 체이닝이 가능하다.
const promise = new Promise(function (resolve, reject) {
// do something async here..
fs.readFile(path, "utf-8", (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
promise.then(function (data) {
console.log("Promise success!", data);
});
promise.catch(function (err) {
console.log("Promise Failed!", err);
});
resolve(결과)
의 결과가 then
의 result로 가고, reject(err)
의 err이 catch
의 err로 간다.
그리고 여러 단계를 아래와 같이 순차적으로 연결할 수도 있다.
(thend과 catch는 Promise 객체의 메소드이다. 만약 then이 또 다른 값을 반환한다면, then을 다음에 한 번 더 연결해서 처리할 수 있다.)
promise.then(function done (data) {
console.log("Promise success!", data);
return 1;
}).then(function handleOne (one) {
console.log("I am one.");
return one + 1;
}).then(function handleTwo (two) {
console.log("I am two.");
}).catch(function handleError (err) {
console.log("Promise Failed!", err);
});
이 메소드는 모든 프로미스가 성공하면 then, 하나라도 실패하면 catch로 연결된다.
개개인의 코딩 스타일에 따라서 then()
의 두 번째 인자로 처리할 수도 있고, catch()
로 처리할 수도 있겠지만, 가급적 catch()
로 에러를 처리하는 것이 더 효율적이다.
function getData() {
return new Promise(function(resolve, reject) {
resolve('hi');
});
}
getData().then(function(result) {
console.log(result);
throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then()
}, function(err) {
console.log('then error : ', err);
});
getDate()
함수의 프러미스에서 resolve()
메서드를 호출해 정상적으로 로직을 처리했지만, then()
첫 번째 콜백 함수 내부에서 오류가 나는 경우 오류를 제대로 잡아내지 못한다.
하지만 똑같은 오류를 catch()
로 처리하면 다른 결과가 나온다.
// catch()로 오류를 감지하는 코드
function getData() {
return new Promise(function(resolve, reject) {
resolve('hi');
});
}
getData().then(function(result) {
console.log(result); // hi
throw new Error("Error in then()");
}).catch(function(err) {
console.log('then error : ', err); // then error : Error: Error in then()
});
위 처리 결과는 다음과 같다.
프러미스를 이용했을때 기존 콜백 지옥과는 몇 가지 큰 차이를 갖는다.
우선
1. 동기 흐름의 코드에서 함수 연산에 대한 결과로서 반환값을 지정할 수 있고,
2. 그 결과를 받아 추가적인 연산을 진행할 수 있다.
콜백 함수를 이용한 상황에서는 비동기 함수의 반환값을 받을 수 없기 때문에, 동기 함수처럼 반환값ㅇ르 지정해줄 수 없었다.
하지만 프러미스를 이용할 결우, (성공이나 실패에 대한 결과를 알려주는) 약속을 담은 객체가 손에 쥐어지기 때문에 프러미스 객체를 이용해 반환하거나 자유롭게 다른 모듈로 넘겨줄 수 있다. 비동기 상황에서도 동기적 코드의 흐름과 조금 더 유사하게 제어할 수 있도록 개선된 것이다.
하지만, 이런 Promise 조차도 Promise hell이 발생할 수 있어, async/await 문법이 등장하게 되었다.