Promisethenメソッドの呼び出しの流れは、promiseと同じです:
- Promise のコンストラクタ・メソッドはコールバック関数 executor() を受け取り、これは new Promise() の直後に実行されます。
- コールバック関数内の非同期タスクは、マクロ/マイクロ・タスク・キューに置かれ、実行を待ちます。
- then()が実行され、成功/失敗コールバックが収集され、成功/失敗キューに置かれます。
- コールバック関数executor()の非同期タスクが実行され、resolve/rejuceがトリガーされます。
Promise
- Promiseは基本的にステートマシンで、状態はPending, Fulfilled, Rejectedの3つしかなく、状態の変化は一方向で、Pending -> FulfilledかPending -> Rejectedしかなく、状態の変化は可逆的ではありません。
- thenメソッドは2つのオプションの引数を取り、それぞれが状態変化によって引き起こされるコールバックに対応します。thenはプロミスを返します。thenは同じプロミスで複数回呼び出すことができます。
const PENDING = 'pending'
cosnt FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this._status = PENDING // Promise
this._resolveQueue = [] // then正常に実行されたコールバックのキューは収集される。
this._rejectQueue = [] // then失敗したコールバックキューを収集する
// resolve/rejectはエクゼキューター内部で呼び出されるので、arrow関数を使って this点を修正する必要がある。._resolveQueue
let _resolve = (val) => {
if (this._status !== PENDING) return // thenメソッドはpromiseを返す。thenメソッドは同じpromiseで複数回呼び出すことができる。これは「状態はpendingからfulfilledかrejectedにしかならない」という仕様に対応している。”
this._status = FULFILLED // 状態を変更する
// コールバックは成功キューから取り出され、順次実行される。
while(this._resolveQueue.length) {
const callback = this._resolveQueue.shift()
callback(val)
}
}
let _reject = (val) => {
if (this._status !== PENDING) return // thenメソッドはpromiseを返す。thenメソッドは同じpromiseで複数回呼び出すことができる。これは「状態はpendingからfulfilledかrejectedにしかならない」という仕様に対応している。”
this._status = REJECTED // 状態を変更する
while(this._rejectQueue.length) {
const callback = this._rejectQueue.shift()
callback(val)
}
}
// new Promise()executorは、resolveとrejectを渡すことで、状態変化が起こったときに即座に実行される。
executor(_resolve, _reject)
}
then(resolveFn, rejectFn) {
this._resolveQueue.push(resolveFn)
this._rejectQueue.push(rejectFn)
}
}