[resolve, then 슈도 코드]
excutor
- resolve와 reject 메서드 바인딩하고 인자로 넘기며 실행
resolve
- 실행 시 then에 등록해둔 콜백들이 순서대로 실행된다
then
- 콜백들을 등록해둔다
- 프로미스를 반환해서 체이닝 이 이어지도록 한다
const MyPromise = class {
constructor(executor) {
// new Promise( excutor )
// 콜백으로 받아와서 resolve reject 넣어줘서 사용 하게끔 한다
this.executor = executor;
this.state = "pending";
this.lastcalls = []; // [callback(this.value)] 가 담기게 된다.
this.executor(this.resolve.bind(this));
}
resolve(value) {
this.value = value;
this.state = "resolved";
this.lastcalls.forEach((lastcall) => {
this.value = lastcall();
// this.value는 처음 넣은 값부터 then 콜백의 리턴 값으로 계속 업데이트 된다
});
// resolve 함수 실행되면 되면 등록해놨던 then 콜백함수들 순서대로 다 실행
}
then(callback) {
if (this.state === "pending") {
this.lastcalls.push(() => callback(this.value)); // 콜백을 등록
// value는 처음 넣은 값부터 then 콜백의 리턴 값으로 계속 업데이트 된다
}
return this; // 다음 체이닝 위해서 프로미스 다시 반환
}
};
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('첫번째 프로미스');
}, 1000);
})
.then(value => { // this.value ( resolve 함수의 argument )
// callback 이 실행되지 않기 때문에 콘솔에 안찍힘
console.log(value); // 나중에 비동기 resolve가 실행된 후 그때 callback이 실행됨
return '두번째 프로미스';
})
.then(value => { // this.value ( 이전 then 콜백 의 return 값 )가 then의 콜백에 전달됨
console.log(value);
});
[완성 코드]
const MyPromise = class {
constructor(executor) { // 프로미스 실행 함수, new Promise( 이 콜백함수 )
this.state = 'pending'; // pending 상태에서 시작
this.laterCalls = []; // 콜백들 모아놓은 배열
this.decidePromiseByMethod.bind(this); // this 바인딩
this.applyChangedState.bind(this); // this 바인딩
try {
executor(this.resolve.bind(this), this.reject.bind(this));
// resolve, reject 콜백함수를 인자로 받아 상황 분기해서 실행
} catch (error) {
this.reject(error);
}
}
// resolve 시 실행할 함수
resolve(value) {
this.applyChangedState(value, 'resolved');
}
applyChangedState(value, state) {
if (!(this.state === 'pending')) return;
if (value instanceof MyPromise) { // 프로미스 인자로 넣었을시 resolve( 여기에다가 )
value.then(innerPromiseValue => {
this.value = innerPromiseValue;
this.status = state; // state resolve로 변경
this.laterCalls.forEach(latercall => latercall());
});
} else { // 그냥 값 넣었을 경우
this.value = value;
this.state = state; // state resolve로 변경
this.laterCalls.forEach(latercall => latercall());
// then 에 등록한 콜백들 다 실행
}
}
// then
then(callback) {
return this.decidePromiseByMethod('then', callback);
}
decidePromiseByMethod(method, callback) {
const state = method === 'then' ? 'resolved' : 'rejected';
if (this.state === state)
return new MyPromise(resolve => resolve(callback(this.value)));
// 콜백을 resolve 로 감싸야지 then 안에서 Promise 반환해도 대응가능
if (this.state === 'pending') // pending 시 콜백에 등록하고 프로미스 리턴
return new MyPromise(resolve => {
this.laterCalls.push(() => resolve(callback(this.value)));
});
return this;
}
reject(value) {
this.applyChangedState(value, 'rejected');
}
catch(callback) {
return this.decidePromiseByMethod('catch', callback);
}
};
module.exports = MyPromise;
참고
Custom Promise 구현으로 프로미스 파혜치기 - p-iknow's devlog