blog

手書きのPromiseコア原則

Promiseの現在の状態は、wait、execute、rejectのいずれかでなければなりません。 Promiseオブジェクトの下にthenメソッドをチェーンする場合、thenメソッドのコールバック...

Feb 21, 2020 · 19 min. read
シェア

Promise解決したこと

  • Promiseはコールバック地獄の問題を解決してくれます。
  • 従来の非同期プログラミングでは、コールバックが早すぎたり、コールバックが遅すぎたり、コールバックがなかったり、コールバックの回数が多すぎたり、といった信頼性の問題がよくありました。
  • Promiseの最大の利点は、プロセスの非同期実行において、実行コードとコードの結果の処理が明確に分離されていることです。

Promiseの最も単純な使い方の1つを見てみましょう。

const p1 = new Promise((resolve, reject) => {
 resolve('success')
})
p1.then((res) => console.log('res'), err => console.log(err))
// success

Promise

  • Promiseはクラスであり、このクラスの実行では、エクゼキュータexecutor()を渡す必要があります。
  • executorはresolveとrejectの2つの引数を取ります。
  • 約束には3つの状態があり、成就した状態、拒否された状態、保留中の状態、そして
  • 約束は保留から拒否になるか、保留から履行になるかのどちらかしかありません。
  • 一度確定した約束の状態を変更することはできません。
  • このメソッドが内部で行うことは、状態を判断し、状態が成功であれば成功コールバック関数を呼び出し、状態が失敗であれば失敗関数を呼び出すことです。
  • プロミスのthenメソッドはプロミスを返します。
  • パラメータonFulfilledとonRejectedはオプションです。
  • 成功コールバックには成功後の値を表すパラメータが1つあり、失敗コールバックには失敗の理由を表すパラメータが1つあります。

プロミスの一般的な構造は次のようになります。


const PENDING = 'pending'; //  
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; //  
class MyPromise {
 constructor (executor) {
 executor(this.resolve, this.reject)
 }
 // promise  
 status = PENDING;
 // 成功後の値
 value = undefined;
 // 失敗後の値
 reason = undefined;
 resolve = () => {
 // 状態がwaitでない場合は、プログラムの実行を途中で止める。
 if (this.status !== PENDING) return;
 // ステータスを成功に変更する
 this.status = FULFILLED;
 // 保存成功後の値
 this.value = value;
 }
 reject = () => {
 // 状態がwaitでない場合は、プログラムの実行を途中で止める。
 if (this.status !== PENDING) return;
 // ステータスを失敗に変更する
 this.status = REJECTED;
 // 保存失敗後の理由
 this.reason = reason;
 }
 then (successCallback, failCallback) {
 // 状態を決定する
 if (this.status === FULFILLED) {
 successCallback();
 } else if (this.status === REJECTED) {
 failCallback()
 }
 }
}

テストしてください。

let p1 = new MyPromise((resolve, reject) => {
 resolve('成功')
})
p1.then((value) => {
 console.log(value)
}, reason => {
 console.log(reason)
})
// 成功

Promise A+

仕様によると、いくつかのコアルールに要約することができます。

  • Promise の現在の状態は、waiting、executing、rejecting の 3 つの状態のいずれかでなければなりません。
  • Promiseのthenメソッドは2つの引数をとります。 promise.then(onFulfiled, onRejected)
  • then メソッドは同じ Promise から複数回呼び出すことができます。
  • then メソッドは Promise オブジェクトを返さなければなりません。

プロミスを導入するためのステップバイステップガイドです。

Promise非同期ロジックを

// コールバック成功 successCallback = undefined; // 失敗時のコールバック faliCallback = undefined; resolve = value => { // 成功コールバックが存在するかどうかを判断し、存在する場合は this.successCallback && this.successCallback(this.value) } reject = reason => { // 失敗コールバックが存在するかどうかを判断し、存在する場合は this.faliCallback && this.faliCallback(this.reason) } then (successCallback, faliCallback) { // 状態を決定する if (this.status === FULFILLED) { successCallback(this.value) } else if (this.status === REJECTED) { faliCallback(this.reason); } else { // // 待機コールバックと失敗コールバックを一緒に保存する this.successCallback = successCallback; this.faliCallback = faliCallback; } }

テストしてください。

let promise = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('success')
 }, 2000)
})
promise.then(value => {
 console.log(value)
}, reason => {
 console.log(reason)
})
// success

複数の呼び出しに対して複数のハンドラを追加するメソッドを実装します。

  • 同期および非同期の状況への対応
  • 同期の場合はコールバック関数を直接呼び出しますが、非同期の場合はコールバック関数を保存する必要があります。
  • まず、成功と失敗のコールバックの値を配列に変換します。
  • そして、成功と失敗のコールバックは、pushメソッドを使って配列にプッシュされます。
  • プロミスの状態が成功や失敗に変わったら、配列内のコールバック関数を順番に呼び出す必要があります。
  • 成功したコールバックの配列の長さが0に等しくない場合は、コールバック関数があり、ループが前から後ろにシフト()メソッドを呼び出すために実行されている間、削除された1つの各実行は、0用の配列の長さまで
successCallback = []; failCallback = []; // 元のコードを // this.successCallback && this.successCallback(this.value); while (this.successCallback.length) this.successCallback.shift()(this.value); // this.faliCallback && this.faliCallback(this.reason); while (this.faliCallback.length) this.faliCallback.shift()(this.reason);

テストしてください。

let promise = new MyPromise((resolve, reject) => {
 // resolve('ビッグ・キャベツ~~~')
 // reject('失敗')
 setTimeout(() => {
 resolve('ビッグ・キャベツ~')
 }, 2000)
})
promise.then(value => {
 console.log(value)
}, reason => {
 console.log(reason)
})
//  

メソッド・チェイニングの実装

  • プロミスのthenメソッドは連鎖させることができ、値を取得するthenメソッドコールバック関数は、実際には最後のthenメソッドコールバック関数の戻り値を取得します。
  • thenメソッドの連鎖呼び出しは、thenメソッドはPromiseオブジェクトの下にあります。

銘記

  • メソッドを連結する場合、コールバック関数は通常の値とプロミスオブジェクトを返すことができます。

  • 返された値が正常値であれば、resolve(x)を直接呼び出して、次のプロミスオブジェクトに正常値を渡すことができます。

  • もしそれがpromiseオブジェクトであれば、返されたpromiseオブジェクトの状態をチェックする必要があります。状態が成功であれば、resolveメソッドを呼び出して成功した状態を渡し、失敗であれば、次のpromiseオブジェクトにrejectを渡す必要があります。

// thenメソッドを修正する
then (successCallback, faliCallback) {
 let promise2 = new myPromise((resolve, reject) => {
 // 状態を決定する
 if (this.status === FULFILLED) {
 let x = successCallback(this.value);
 // xが通常の値かPromiseオブジェクトかを判定する
 // 普通の値なら、resolveを呼べばいい。
 // これがPromiseオブジェクトの場合は、Promiseオブジェクトが返す結果を見る。
 // resovleを呼ぶかrejectを呼ぶかの判断は、Promiseオブジェクトが返す結果に基づいている。
 resolvePromise(x, resolve, reject)
 // resolve(x)
 } else if (this.status === REJECTED) {
 faliCallback(this.reason);
 } else {
 //  
 // 待機コールバックと失敗コールバックを一緒に保存する
 this.successCallback.push(successCallback);
 this.faliCallback.push(faliCallback);
 }
 });
 return promise2;
}
// resolvePromiseメソッドを定義する
function resolvePromise(x, resolve, reject) {
 if (x instanceof myPromise) {
 // promise 
 x.then(resolve, reject);
 } else {
 //  
 }
}
// テストしてみよう。
let promise = new MyPromise((resolve, reject) => {
 resolve('ビッグ・キャベツ~~~')
 // reject('失敗')
 // setTimeout(() => {
 // resolve('ビッグ・キャベツ~')
 // }, 2000)
})
function other () {
 return new MyPromise((resolve, reject) => {
 resolve('other');
 })
}
promise.then(value => {
 console.log(value);
 return other();
}).then(value => {
 console.log(value)
})
//  
// other

Promiseのメソッドチェイン呼び出しは、Promiseオブジェクトを自動的に返します。

Promiseオブジェクトの下でthenメソッドの呼び出しを連鎖させる場合、thenメソッドコールバック関数はPromiseオブジェクトを返すことができますが、我々は別の状況を考慮する必要があります、thenメソッドコールバック関数では、彼がPromiseオブジェクトを返した現在のthenメソッドを返すことはできません、thenメソッドがPromiseオブジェクトを返す場合、循環呼び出しが発生します。thenメソッドによって返されたPromiseオブジェクトを返す場合、循環呼び出しが発生します。

代表例

let promise = new Promise((resolve, reject) => {
 resolve('キャベツ')
})
let p1 = promise.then((value) => {
 console.log(value)
 return p1
})
//  
// TypeError: Chaining cycle detected for promise #<Promise>

つり具

  • then メソッドで返される Promise オブジェクトは Promise 2 です。
  • コールバックが成功すると、Promiseオブジェクトが返されます。
  • peomise2がxに等しいかどうかを判定します。,
  • 自分を戻すのと同じで、状態をリジェクトに入れる必要があります。

修正コード

// setTimeout()を追加して、thenメソッド内を非同期コードに変換する。
setTimeout(() => {
 // 実行に成功すると、successコールバック関数が呼び出され、戻り値が取得される。
 let x = successCallback(this.value);
 resolvePromise(promise2, x, resolve, reject)
}, 0)
// resolvePromiseメソッドを修正する
function resolvePromise (promise2, x, resolve, reject) {
 // 等しいかどうかの判定
 if (promise2 === x) {
 return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
 }
 if (x instanceof MyPromise) {
 // promise  
 x.then(resolve, reject)
 } else {
 //  
 resolve(x)
 }
}

テストしてください。


let promise = new MyPromise((resolve, reject) => {
 resolve('キャベツ')
})
let p1 = promise.then((value) => {
 console.log(value)
 return p1
})
p1.then((value) => {
 console.log(value)
}, (err) => {
 console.log(err)
})
//  
// Chaining cycle detected for promise #<Promise>

エラーをキャッチし、他のステートへの呼び出しを連鎖させます。

実行コンストラクタにtry catchを追加

constructor (executor) {
 try {
 executor(this.resolve, this.reject)
 } catch (e) {
 this.reject(e);
 }
}
// テストしてみよう。
let promise = new myPromise((resolve, reject) => {
 throw new Error('executor error')
})
promise.then(value => {
 console.log(value)
}, reason => {
 console.log(reason.message)
})
// エラーエクスキューターエラーをキャッチすることに成功した

コールバック関数はエラーをキャッチします。

// thenメソッドのsetTimeoutにtry catchを追加する
setTimeout(() => {
 try {
 let x = successCallback(this.value);
 resolvePromise(promise2, x, resolve, reject)
 } catch (e) {
 reject(e)
 }
}, 0)
//  
let promise = new MyPromise((resolve, reject) => {
 resolve('キャベツ')
})
promise.then((value) => {
 console.log(value)
 throw new Error('then error')
}, (err) => {
 console.log(err.message)
}).then((value) => {
 console.log(value)
}, reason => {
 console.log('~~~')
 console.log(reason.message)
})
//  
// ~~~
// then error

故障の修正

setTimeout(() => {
 try {
 let x = failCallback(this.reason);
 resolvePromise(promise2, x, resolve, reject)
 } catch (e) {
 reject(e)
 }
}, 0)
// テストしてみよう。
let promise = new MyPromise((resolve, reject) => {
 reject('失敗')
})
promise.then(value => {
 console.log(value)
}, reason => {
 console.log(reason)
 return 'グレート・ホワイト~~~';
}).then(value => {
 console.log(value)
})
//  
// 白菜~~~~。

非同期の場合

元のコードを次のように変更します。

this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
this.successCallback.push(() => {
 setTimeout(() => {
 try {
 let x = successCallback(this.value);
 resolvePromise(promise2, x, resolve, reject)
 } catch (e) {
 reject(e)
 }
 }, 0)
})
this.failCallback.push(() => {
 setTimeout(() => {
 try {
 let x = failCallback(this.reason);
 resolvePromise(promise2, x, resolve, reject)
 } catch (e) {
 reject(e)
 }
 }, 0)
})
// では、resolveとrejectに値を渡す必要はない。
while (this.successCallback.length) this.successCallback.shift()();
while (this.failCallback.length) this.failCallback.shift()();

テストしてください。

let promise = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('success~~~~');
 // reject('error~~~~')
 }, 2000)
})
promise.then((value) => {
 console.log(value)
 return ' ;
}, reason => {
 console.log(reason)
 return '白菜の;
}).then((value) => {
 console.log(value);
})
// suceess~~~
//  

プロミスのコア機能は基本的にここに実装されています。

メソッドの引数をオプションに

  • thenメソッドには、成功コールバックと失敗コールバックの2つのオプションのパラメータがあります。
  • これらのパラメータはどちらもオプションで、以下の場合に追加されます。
let promise = new Promise((resolve, reject) => {
 resolve(100)
})
promise
 .then()
 .then()
 .then(value => {
 cosole.log(value)
 })
  • この場合、約束は指揮命令系統の下に伝えられます。
  • thenメソッドにパラメータがあるかどうかを判断し、なければパラメータを作成して、状態を順番に後方に渡せるようにする必要があります。
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => { throw reason };

テストしてください。

let promise = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('success');
 // reject('reject');
 }, 2000)
})
promise.then().then().then(value => {
 console.log(value);
}, reason => {
 console.log(reason);
})
// success
// reject

Promise.all

  • 通常の値やPromiseオブジェクトを含む任意の値で埋めることができます、配列の順序は、結果の順序でなければなりません。
  • Promise.allはすべてのPromiseオブジェクトをallで表現し、その状態が成功すればallメソッドは成功し、失敗すれば失敗します。
  • クラスを使用します。Allはスタティック・メソッドなので、allはスタティック・メソッドです。
  • Promise.allは非同期同時実行の問題を解決するもので、非同期コードが呼び出された順番に実行できるようにします。allメソッドは静的メソッドで、allの前にstaticキーワードが定義されています。allメソッドはパラメータとして配列を受け取り、allメソッドの戻り値はPromiseオブジェクトで、Promiseオブジェクトに渡された配列に対してループを通して呼び出され、ループの過程で通常の値かPromiseオブジェクトかを判断し、異なる呼び出しが行われます。Promiseオブジェクトでは、配列をループに通し、ループの過程で正常値かPromiseオブジェクトかを判断し、異なる呼び出しを行います。
  • 引数のいずれかでPromiseが失敗した場合、Promise.allが返すProiseオブジェクトは失敗します。
static all(array) {
 let result = []
 let index = 0
 return new MyPromise((resolve, reject) => {
 // 非同期処理でforループを実行し、非同期処理を待たずにループを実行する。
 // indexが配列の長さと等しい場合、resolveが呼ばれる。
 function addData (key, value) {
 result[key] = value;
 index++ 
 if (index === array.length) {
 resolve(result)
 }
 }
 // 通常の値なのか、Promiseオブジェクトなのかを判断する必要がある。
 for (let i = 0; i < array.length; i++) {
 let current = array[i];
 if (current instanceof MyPromise) {
 // promise  
 current.then(value => addData(i, value), reason => reject(reason) )
 } else {
 //  
 addData(i, array[i])
 }
 }
 })
}

テストしてください。

function p1() {
 return new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('p1')
 }, 1000)
 })
}
function p2() {
 return new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('p1')
 }, 1000)
 })
}
MyPromise.all(['a', 'b', p1(), p2(), 'c']).then(result => {
 console.log(result)
})
// [ 'a', 'b', 'p1', 'p1', 'c' ]

Promise.resolve メソッドの実装

  • Promise.resolveの役割は、与えられた値をPromiseオブジェクトに変換することです。つまり、Promise.resolveの返り値はPromiseオブジェクトであり、返されたPromiseオブジェクトは与えられた値にラップされます。
  • 内部のresolveでは、Promiseオブジェクトを作成し、Promiseオブジェクトにラップされた値、およびresolveの戻り値として最もPromiseオブジェクトの作成は、それがこのため、呼び出しの連鎖に従うことができるその後、メソッドは、値を取得するメソッドコールバック関数の成功は、Promise.resolveはまた、Promiseオブジェクトを受信することができますPromise.resolve内部では、与えられた値が通常の値またはPromiseオブジェクトであるかどうかを判断しますPromise.resolve内部では、通常の値またはPromiseオブジェクトであるかどうかを判断しますPromise.resolve内部では、与えられた値が通常の値またはPromiseオブジェクトであるかどうかを判断しますPromise.resolve内部では、与えられた値が通常の値またはPromiseオブジェクトであるかどうかを判断します。Promise.resolveはまた、Promiseオブジェクトを受け取ることができ、Promise.resolveで、それがPromiseオブジェクトである場合、それは戻り値としてPromise.resolveで元のPromiseになりますので、指定された値は、通常の値またはPromiseオブジェクトであるかどうかを判断します。メソッドを呼び出した後、Promiseオブジェクトの戻り値を取得するためにメソッドの成功コールバック関数を介して
static resolve(value) {
 if (value instanceof myPromise) return value;
 return new MyPromise(resolve => resolve(value))
}

テストしてください。

function p1() {
 return new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('p1')
 }, 1000)
 })
}
MyPromise.resolve('キャベツ').then(value => console.log(value))
MyPromise.resolve(p1()).then(value => console.log(value))
//  
// p1

Promise.reject()

static reject(reason) {
 return new MyPromise((resolve,reject) => reject(reason))
}

Promise.finallyメソッドの実装

Promise.finallyには2つの特徴があります。

  • コールバック関数であるfinallyメソッドは、Promiseオブジェクトの最終的な状態(成功、失敗)に関係なく、常に一度だけ実行されます。
  • 現在のPromiseオブジェクトの最終結果を得るために、finallyの後にthenメソッドを連鎖的に呼び出すことができます。
finally(callback) {
 return this.then(value => {
 callback();
 return value
 }, reason => {
 callback();
 throw reason
 })
}

テストしてください。

function p1() {
 return new MyPromise((resolve, reject) => {
 resolve('p1 reject')
 // reject('p1 reject')
 })
}
function p2() {
 return new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('p2')
 }, 2000)
 })
}
p1().finally(() => {
 console.log('finally');
 // return p2();
}).then(value => {
 console.log(value);
}, reason => {
 console.log(reason);
})
// finally
// p1 reject
  • finallyコールバック関数の中で、実際にPromiseオブジェクトを返すことができます。
  • returnの後、p2はsetTimeoutが実行されるのを待つ必要があります。
  • resolveメソッドの助けを借りて
  • コールバックが普通の値を返す場合、Promiseオブジェクトを変換し、Promiseオブジェクトが実行を完了するのを待つだけでなく、返り値で、実行を完了するのを待ちます上記のコードの最適化
finally(callback) {
 return this.then(value => {
 return MyPromise.resolve(callback()).then(() => value);
 }, reason => {
 return MyPromise.resolve(callback()).then(() => { throw reason },);
 })
}

テストしてください。

function p1() {
 return new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('p1 resolve')
 }, 2000)
 })
}
function p2() {
 return new MyPromise((resolve, reject) => {
 resolve('p2 resolve')
 // reject('p2 reject')
 })
}
p2().finally(() => {
 console.log('finally');
 return p1()
}).then(value => {
 console.log(value);
}, reason => {
 console.log(reason);
})
// finally 
// 2秒待ち、出力p2 resolveを実行する。

Promise.catch メソッドの実装

  • catchメソッドの役割は、失敗の最終的な状況のためにPromiseオブジェクトの現在の状態に対処するために使用される、つまり、呼び出し時メソッドは、コールバックの失敗を渡すことができない場合は、コールバックの失敗を渡さない場合は、コールバックの失敗は、catchメソッドに渡されたコールバック関数を実行するように、catchによってキャッチすることができます。
  • catchメソッドの中に入って、thenメソッドを呼び出すだけです。
catch (failCallback) {
 return this.then(undefind, failCallback);
}

テストしてください。

function p1() {
 return new MyPromise((resolve, reject) => {
 // resolve('ビッグ・キャベツ~~~')
 reject('error')
 })
}
p1()
 .then(value => console.log(value))
 .catch(reason => console.log(reason))

Promise.race()

static race(promises) {
 return new MyPromise((resolve, reject) => {
 if (promises.length === 0) {
 return
 } else {
 for (let p of promises) {
 MyPromise.resolve(p).then(value => {
 resolve(value)
 }, reason => {
 reject(reason)
 })
 } 
 }
 })
}

テストしてください。

const MyPromise = require('./myPromise');
let promise1 = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('キャベツ')
 }, 2000)
});
let promise2 = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve('ライスケイク')
 }, 1000)
});
MyPromise.race([promise1, promise2]).then((value) => {
 console.log(value);
});
//  

フルコード

const PENDING = 'pending'; // const FULFILLED = 'fulfilled'; // 成功 const REJECTED = 'rejected'; // class MyPromise { constructor (executor) { try { executor(this.resolve, this.reject) } catch (e) { this.reject(e); } } // promise status = PENDING; // 成功後の値 value = undefined; // 失敗後の値 reason = undefined; // コールバック成功 successCallback = []; // 失敗時のコールバック failCallback = []; resolve = value => { // 状態がwaitでない場合は、プログラムの実行を途中で止める。 if (this.status !== PENDING) return; // ステータスを成功に変更する this.status = FULFILLED; // 保存成功後の値 this.value = value; // 成功コールバックが存在するかどうかを判断し、存在する場合は // this.successCallback && this.successCallback(this.value); while (this.successCallback.length) this.successCallback.shift()(); } reject = reason => { // 状態がwaitでない場合は、プログラムの実行を途中で止める。 if (this.status !== PENDING) return; // ステータスを失敗に変更する this.status = REJECTED; // 保存失敗後の理由 this.reason = reason; // 失敗コールバックが存在するかどうかを判断し、存在する場合は // this.faliCallback && this.faliCallback(this.reason); while (this.failCallback.length) this.failCallback.shift()(); } then (successCallback, failCallback) { // 仕様によると、thenの引数が関数でない場合、それは無視される必要があり、連鎖した呼び出しが下に続くことになる。 successCallback = typeof successCallback === 'function' ? successCallback : value => value; failCallback = typeof failCallback === 'function' ? failCallback : reason => { throw reason }; let promise2 = new MyPromise((resolve, reject) => { // 状態を決定する if (this.status === FULFILLED) { setTimeout(() => { try { let x = successCallback(this.value); // xが通常の値かPromiseオブジェクトかを判定する // 普通の値なら、resolveを呼べばいい。 // これがPromiseオブジェクトの場合は、Promiseオブジェクトが返す結果を見る。 // resovleを呼ぶかrejectを呼ぶかの判断は、Promiseオブジェクトが返す結果に基づいている。 resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } else if (this.status === REJECTED) { setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } else { // // 待機コールバックと失敗コールバックを一緒に保存する this.successCallback.push(() => { setTimeout(() => { try { let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) // 成功コールバックを this.failCallback.push(() => { setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) // 失敗コールバックを } }); return promise2; } static all(array) { let result = [] let index = 0 return new MyPromise((resolve, reject) => { // 非同期処理でforループを実行し、非同期処理を待たずにループを実行する。 // indexが配列の長さと等しい場合、resolveが呼ばれる。 function addData (key, value) { result[key] = value; index++; // すべての項目が実行されるようにする if (index === array.length) { resolve(result); } } // 通常の値なのか、Promiseオブジェクトなのかを判断する必要がある。 for (let i = 0; i < array.length; i++) { let current = array[i]; if (current instanceof MyPromise) { // promise current.then(value => addData(i, value), reason => reject(reason)); } else { // addData(i, array[i]) } } }) } static resolve(value) { if (value instanceof MyPromise) return value; return new MyPromise(resolve => resolve(value)) } static reject(reason) { return new MyPromise((resolve,reject) => reject(reason)) } static race(promises) { return new MyPromise((resolve, reject) => { if (promises.length === 0) { return } else { for (let p of promises) { MyPromise.resolve(p).then(value => { resolve(value) }, reason => { reject(reason) }) } } }) } // finally連鎖はPromiseを返す。 finally(callback) { return this.then(value => { return MyPromise.resolve(callback()).then(() => value); }, reason => { return MyPromise.resolve(callback()).then(() => { throw reason },); }) } catch (failCallback) { return this.then(undefined, failCallback); } } function resolvePromise (promise2, x, resolve, reject) { // 等しいかどうかの判定 if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) } if (x instanceof MyPromise) { // promise x.then(resolve, reject) } else { // resolve(x) } } module.exports = MyPromise;

まとめると

上記は、プロミスの全体のプロセスの実装では、まずすべてのプロミスコアの分析の始まりの使用の簡単なプロミスの例から、大まかな構造の実装の分析によると、その後、コードを埋めるためにステップバイステップでプロミスA +仕様によるとです。の主な実装

  • Promise 非同期ロジック
  • 複数の呼び出しに対して複数のハンドラを追加するメソッドを実装します。
  • Promise.then()メソッドの連鎖
  • Promise.then()パラメータはオプションです
  • Promise.all()
  • Promise.resolve()
  • Peomise.reject()
  • Promise.finally()
  • Promise.catch()
  • Promise.rece()

Read next

MySQL チューニング: 低速一括インサート(540倍のパフォーマンス向上)

1.はじめに 数日前、ストアドプロシージャを使って10Wのデータを書き込むというMySQLのテスト実験をしていたところ、1時間以上かかることがわかりました。私はInnoDBの原理を勉強しており、この目的のために分析とチューニングをしようと考えました。 2.環境 3.分析 データベースにデータを書き込む際には、binlogとredolog ...

Feb 21, 2020 · 4 min read