씹고 뜯고 맛봐야 비로소 이해할 수 있다. promise 너도 그렇다.
//다음과 같이 실행되는 나만의 Promise 함수를 작성하시오.
const p = new Promise((resolve, reject) => {
setTimeout(() => {
const now = Date.now();
if (now % 2 === 0)
resolve(console.log('fulfill', now));
else reject(new Error('어디로?'));
}, 1000);
});
console.log('111>>', p);
setTimeout(() => console.log('222>>', p), 2000);
function Promise(cb) {
}
빌트인 객체인 new promise를 사용하지 않는다.
생성자함수를 사용한다.
const p = new HjPromise((resolve, reject) => {
new를 사용했기에.
생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없습니다. 다만 생성자 함수는 아래 두 관례를 따릅니다.
-함수 이름의 첫 글자는 대문자로 시작합니다.
-반드시 'new' 연산자를 붙여 실행합니다.
p가 가진 값은 프로미스 객체처럼 보여야한다는 것
resolve
와 reject
함수(메서드) 를 가지고 있다.
const p = new HjPromise((resolve, reject) => {
setTimeout(() => {
const now = Date.now();
if (now % 2 === 0)
resolve(console.log('fulfill', now));
else reject(new Error('어디로?'));
}, 1000);
});
console.log('111>>', p);
setTimeout(() => console.log('222>>', p), 2000);
function HjPromise(cb) {
this.state = "<pending>";
const resolve = (res) => {
console.log("성공>>>", res);
this.state = "<resolve>";
};
const reject = (error) => {
console.log("실패>>>", error);
this.state = "<reject>";
return this.state;
};
cb(resolve, reject);
}
const p = new HjPromise();
function HjPromise(cb) {}
console.log("111>>", p);
이렇게만 찍으면 111>> HjPromise {}
이렇게 나오게 된다.
빈 객체가 생성된 것이다.
이 객체에 상태값을 주기위해선 this
를 할당하고 this
에 새로운 프로퍼티를 추가해서 this
를 수정하고 반환하는 식으로 작동 시킵니다.
this
에 새로운 프로퍼티를 추가한다.function HjPromise(cb) {
this.state = "<pending>";
}
console.log("111>>", p);
//결과값
// 111>> HjPromise { state: '<pending>' }
HjPromise 객체에 state 프로퍼티가 추가된 것을 볼 수 있다. 이 상태가 우리가 promise를 말할 때 아무일도 시작안한 상태 pending 값이다.
// callback을 위한 메서드 생성
const resolve = (res) => {
console.log("성공===>", res);
this.state = "<resolve>";
};
const reject = (error) => {
console.log("실패===>", error);
this.state = "<reject>";
};
여기서 중요한점 resolve & reject 함수를 작성할 때는 반드시 화살표 함수를 사용해야한다. 왜냐하면 화살표 함수의 경우 상위 스코프의 this를 바인딩 하기 때문인데, 여기서 function(){} 을 사용하면 상황에 따른 바인딩이 되긴하지만, 대체로 전역공간의 this, 또는 메소드 호출 시 메소드 내부의 this를 바인딩한다. 하지만 화살표 함수는 화this라는 변수 자체가 존재하지 않기 때문에 그 상위 환경에서의 this를 참조하게 된다.
Resolve
if (now % 2 === 0) resolve(console.log("fulfill", now));
resolve 함수를 탄 인자는 resolve 함수의 매개변수로 들어와서 res로서 활용된다.
성공의 값을 찍어주고 this.state 를 resolve로 재할당한다.
Reject
else reject(new Error("어디로?"));
Reject 함수를 탄 인자는 Reject 함수의 매개변수로 들어와서 error로서 활용된다.
new Error로 던져진 값을 에러와 함께 출력한다.
function HjPromise(cb) {
//this에 새로운 프로퍼티 추가
this.state = "<pending>";
...(중략)
cb(resolve, reject);
여기서 우린 매개변수로 받아온 cb(콜백함수)에 이 함수(메서드)들을 태워서 보내야한다. 여기 cb는 어떻게 생긴 놈인지 알고 있는가? 다시 위로 올라가보자.
const p = new HjPromise((resolve, reject) => {
setTimeout(() => {
const now = Date.now();
if (now % 2 === 0) resolve(console.log("fulfill", now));
else reject(new Error("어디로?"));
}, 1000);
});
여기서 cb를 추려낼 수 있는 사람?
여기서 cb는 HjPromise의 인자이다.
(resolve, reject) => {
setTimeout(() => {
const now = Date.now();
if (now % 2 === 0) resolve(console.log("fulfill", now));
else reject(new Error("어디로?"));
}, 1000);
}
//
cb(resolve, reject);
이만큼이 콜백함수이다. 약간은 cb(resolve, reject);
이 모습과 닮아있지 않은가? 타고타고타고타고타고 들어가는 함수형 프로그래밍을 이해해야한다.
마지막으로 return this.state
를 해주면 원하는 결과를 출력할 수 있다.
성공시!
실패시!
function myPromise(cb) {
myPromise.prototype.then = (tcb) => {
myPromise.prototype.thenFn = tcb;
return this;
};
myPromise.prototype.catch = (ccb) => {
myPromise.prototype.catchFn = ccb;
return this;
};
const resolve = (succ) => {
console.log("RESOLVE!!👍🏽", succ);
this.state = "resolve";
this.thenFn(succ);
};
const reject = (error) => {
console.log("REJECT!!👎🏽", error);
this.state = "reject";
this.catchFn(error);
};
cb(resolve, reject);
if (new.target) this.state = "pending";
}
Promise 가지고 있는 resolve와 reject의 쓰임에 대해 이해하니 promise가 좀 더 가까워진 기분이다. 앞으로 new Promise를 사용할 때도 내가 만든 코드마냥 내부를 이해하며 사용할 수 있겠지. 그러길빈다.
SSAC 영등포 교육기관에서 풀스택 실무 프로젝트 과정을 수강하고 있다. JS전반을 깊이 있게 배우고 실무에 사용되는 프로젝트를 다룬다. 앞으로 그 과정 중의 내용을 블로그에 다루고자 한다.