JavaScript로 자신만의 Promise 구현
보기보다 복잡하지 않으니 걱정하지 마세요.
이 포스트에서 우리는 기본적인 Promise API를 직접 구현할 것입니다.
약속이란 무엇입니까?
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
다음 세 가지 상태 중 하나일 수 있습니다.
Note: A promise is said to be settled when it is either fulfilled or rejected. (we are going to use this term a lot in this article)
약속을 어떻게 사용합니까?
먼저 약속을 구현하기 위한 골격, 기본적으로 필요한 입력, 노출하는 메서드를 살펴보겠습니다.
콜백을 받는 생성자 함수와 then, catch 및 finally와 같은 메서드가 있습니다.
const promise = new Promise((resolve, reject) => {
/*
Your code logic goes here and you call resolve(value)
or reject(error) to resolve or reject the promise
*/
})
promise.then((value) => {
// Code logic on success of an operation
}).catch(error => {
// Code logic on failure of an operation
}).finally(() => {
// Code logic to be executed after completion of operation
})
1. 스켈레톤 정의
Promise 클래스 MyPromise를 정의하는 것으로 시작합니다.
생성자에 정의된 속성은 다음과 같습니다.
state
: PENDING
, FULFILLED
또는 REJECTED
handlers
: then, catch, finally 메서드의 콜백을 저장합니다. (핸들러는 Promise가 해결되었을 때만 실행됩니다.) value
: 값을 확인하거나 거부합니다. 참고: Promise는 생성되자마자 실행됩니다. 즉, Promise 콜백 함수는
reject
및 resolve
메서드가 매개변수로 전달된 생성자 내부에서 호출됩니다.
const STATE = {
PENDING: 'PENDING',
FULFILLED: 'FULFILLED',
REJECTED: 'REJECTED',
}
class MyPromise {
constructor(callback) {
// Initial state of Promise is empty
this.state = STATE.PENDING;
this.value = undefined;
this.handlers = [];
// Invoke callback by passing the _resolve and the _reject function of our class
try {
callback(this._resolve, this._reject);
} catch (err) {
this._reject(err)
}
}
_resolve = (value) => {}
_reject = (error) => {}
then(onSuccess, onFail) {
}
catch(onFail) {
}
finally(callback) {
}
}
2. _resolve() 및 _reject() 메서드 구현
_resolve()
또는 _reject()
는 promise의 state
를 각각 FULFILLED
또는 REJECTED
로 설정하고 value
속성을 업데이트하고 연결된 핸들러를 실행합니다.Note: Nothing happens if we try to call
_resolve()
or_reject()
on an already settled Promise.
_resolve = (value) => {
this.updateResult(value, STATE.FULFILLED);
}
_reject = (error) => {
this.updateResult(error, STATE.REJECTED);
}
updateResult(value, state) {
// This is to make the processing async
setTimeout(() => {
/*
Process the promise if it is still in a pending state.
An already rejected or resolved promise is not processed
*/
if (this.state !== STATE.PENDING) {
return;
}
// check is value is also a promise
if (isThenable(value)) {
return value.then(this._resolve, this._reject);
}
this.value = value;
this.state = state;
// execute handlers if already attached
this.executeHandlers();
}, 0);
}
위의 코드에서
isThenable(value)
가 무엇인지 궁금하십니까?다른 Promise로 Promise가 해결/거부된 경우에는 완료될 때까지 기다렸다가 현재 Promise를 처리해야 합니다.
isThenable() 함수 구현
isThenable
함수는 값이 MyPromise
의 인스턴스인지 또는 then
함수를 포함하는 객체인지 확인합니다.function isThenable(val) {
return val instanceof MyPromise;
}
// or
function isThenable(value) {
if (typeof value === "object" && value !== null && value.then && typeof value.then === "function") {
return true;
}
return false;
}
3. then() 메소드 구현
then()
메서드는 두 개의 인수를 콜백onSuccess
및 onFail
로 사용합니다. onSuccess
는 약속이 이행되면 호출되고 onFail
는 약속이 거부되면 호출됩니다.“Remember that Promises can be chained”.
The essence of Promise chaining is that thethen()
method returns a new Promise object. That is how promises can be chained. This is especially useful in scenarios where we need to execute two or more asynchronous operations back to back, where each subsequent operation starts when the previous operation succeeds, with the result from the previous step.
then()
에 전달된 콜백은 handlers
함수를 사용하여 addHandlers
배열에 저장됩니다. 핸들러는 promise가 처리될 때 실행될 객체{onSuccess, onFail}
입니다.then()
구현은 다음과 같습니다.then(onSuccess, onFail) {
return new MyPromise((res, rej) => {
this.addHandlers({
onSuccess: function(value) {
// if no onSuccess provided, resolve the value for the next promise chain
if (!onSuccess) {
return res(value);
}
try {
return res(onSuccess(value))
} catch(err) {
return rej(err);
}
},
onFail: function(value) {
// if no onFail provided, reject the value for the next promise chain
if (!onFail) {
return rej(value);
}
try {
return res(onFail(value))
} catch(err) {
return rej(err);
}
}
});
});
}
addHandlers(handlers) {
this.handlers.push(handlers);
this.executeHandlers();
}
executeHandlers() {
// Don't execute handlers if promise is not yet fulfilled or rejected
if (this.state === STATE.PENDING) {
return null;
}
// We have multiple handlers because add them for .finally block too
this.handlers.forEach((handler) => {
if (this.state === STATE.FULFILLED) {
return handler.onSuccess(this.value);
}
return handler.onFail(this.value);
});
// After processing all handlers, we reset it to empty.
this.handlers = [];
}
4. catch() 메소드 구현
catch()
는 then()
를 사용하여 구현됩니다. then()
콜백을 onSuccess
로 사용하여 null
메소드를 호출하고 onFail
콜백을 두 번째 인수로 전달합니다.
/*
Since then method take the second function as onFail,
we can leverage it while implementing catch
*/
catch(onFail) {
return this.then(null, onFail);
}
5. finally() 메서드 구현
finally()
메서드 구현을 시작하기 전에 먼저 동작을 이해하도록 합시다.MDN 문서에서:
The
finally()
method returns aPromise
. When the promise is settled, i.e either fulfilled or rejected, the specified callback function is executed. This provides a way for code to be run whether the promise was fulfilled successfully or rejected once thePromise
has been dealt with.The
finally()
method is very similar to calling.then(onFinally, onFinally)
however there are a couple of differences:When creating a function inline, you can pass it once, instead of being forced to either declare it twice, or create a variable for it
Unlike
Promise.resolve(2).then(() => {}, () => {})
(which will be resolved withundefined
),Promise.resolve(2).finally(() => {})
will be resolved with2
.Similarly, unlike
Promise.reject(3).then(() => {}, () => {})
(which will be fulfilled withundefined
),Promise.reject(3).finally(() => {})
will be rejected with3
.
finally()
메서드는 이전 fulfilled
또는 rejected
값으로 정산될 약속을 반환합니다. // Finally block returns a promise which fails or succeedes with the previous promise resove value
finally(callback) {
return new MyPromise((res, rej) => {
let val;
let wasRejected;
this.then((value) => {
wasRejected = false;
val = value;
return callback();
}, (err) => {
wasRejected = true;
val = err;
return callback();
}).then(() => {
// If the callback didn't have any error we resolve/reject the promise based on promise state
if(!wasRejected) {
return res(val);
}
return rej(val);
})
})
}
아래 codepen에서 전체 코드 구현을 확인하십시오.
요약
우리는 Promise의 기본 구현을 에뮬레이트했습니다. 인스턴스 메소드인
then()
, catch()
, finally()
메소드보다 훨씬 더 많은 것이 있습니다. 앞으로의 게시물에서 다루려고 하는 정적 메서드도 있습니다.나는 당신이 기사를 즐겼기를 바랍니다.
읽어 주셔서 감사합니다...
제안이나 질문이 있으시면 언제든지 댓글이나
Reference
이 문제에 관하여(JavaScript로 자신만의 Promise 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/shubhamreacts/implement-your-own-promises-in-javascript-45cg텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)