まず最初に、プロミスの基本的なルールを示す必要があります:
-約束には3つの状態があります:保留、成就、拒絶。
-ペンディングは初期状態であり、フルフィルドとリジェクトに変換することができます。
-成功した場合、他の状態に移行することはできません。
-失敗時に別の状態に変換されず、不変の原因を持つこと。
- new Promise(=>{resolve(value)}) resolve for success, receive argument value, state changed to fullfilled and cannot be changed again.
- new Promise(=>{reject(reason)}) rejectは失敗で、引数reasonを受け取り、状態をrejectedに変更します。
実行関数がエラーを報告した場合、reject()を実行します。 - 実行関数がエラーを報告した場合、reject()を直接実行します。
class MyPromise{
constructor(executor){
//まず、ステート、resolveのパラメータ、rejectのパラメータを定義する。
this.state='pending';
this.value=undefined;
this.reason=undefined;
let resolve=(value)=>{
//保留状態かどうかを判断する理由は、一度満たされた保留状態を変更できないようにするためである。
if(this.state=='pending'){
this.state='fulfilled'
this.value=value;
}
}
let reject=(reason)=>{
if(this.state=='pending'){
this.state='rejected'
this.reason=reason;
}
}
try{
executor(resolve,reject)
}catch(err){
reject(err)
}
}
}
then
- Promise thenメソッドには2つのパラメータがあります:onFulfilled、onRejected、successにはsuccess値、failureにはfailure原因を指定します。
class MyPromise{
constructor(executor){...}
then(onFulfilled,onRejected){
if(this.state=='fulfilled'){
onFulfilled(this.value)
}
if(this.state=='rejected'){
onRejected(this.reason)
}
}
}
非同期実装の解決
let p1=new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(' ')
},100)
})
p1.then((value)=>{
console.log(value)
},(err)=>{
console.log(err)
})
- resolveがsetTimeoutに入っているときは、thenの状態は常に保留状態なので、resolveはthenでは全く実行されません。そのため、thenが呼び出されて状態が保留状態になったときに、successとfailureをそれぞれの配列に格納する必要があります。rejectまたはresolveが実行されたら、それらを呼び出します。
- プロミスは複数持つことができるので、同じ配列に存在します。
class MyPromise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功も同じ配列に格納される。
this.onResolvedCallbacks = [];
// 失敗はメソッド配列に格納される。
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// resolveが実行されると、success配列の関数が呼び出される。
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// rejectが実行されると、failure配列の関数が呼び出される。
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 状態が保留中の場合
if (this.state === 'pending') {
// onFulfilled成功配列に渡す
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected失敗配列に渡す
this.onRejectedCallbacks.push(()=>{
onRejected(this.value);
})
}
}
}
let p1=new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(' ')
},100)
})
p1.then((value)=>{
console.log(value) //' '
},(err)=>{
console.log(err)
})