https://juejin.cn/post/6994594642280857630
初始架构
- 在
promise实例被构造的时候,构造方法参数(resolve, reject)⇒{} 是立即执行的,所以这个函数参数要在constructor构造器中调用。
- 共有三种状态,
pending,fulfilled,rejected,需要初始化状态为 pending,结果值为null
- 避免之后调用
resolve/reject时,this状态改变,初始化时需要绑定this
- 一旦
pending状态变更后,状态不能再改变,所以执行resolve/reject时需要加上条件判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class MyPromise { constructor(executor) { this.initValue(); this.initBind(); executor(this.resolve, this.reject); }
initBind() { this.resolve = this.resolve.bind(this); this.reject = this.reject.bind(this); }
initValue() { this.PromiseResult = null; this.PromiseState = "pending"; }
resolve(value) { if (this.PromiseState !== "pending") return; this.PromiseState = "fulfilled"; this.PromiseResult = value; }
reject(reason) { if (this.PromiseState !== "pending") return; this.PromiseState = "rejected"; this.PromiseResult = reason; } }
|
另外,如果promise中有throw的话,就相当于执行了reject。这就要使用try catch了
1 2 3 4 5 6 7
| try { executor(this.resolve, this.reject); } catch (e) { this.reject(e); }
|
Promise 的 Then
then接收两个回调,一个是成功回调,一个是失败回调
- 当
Promise状态为fulfilled执行成功回调,为rejected执行失败回调
- 如
resolve或reject在定时器里,则定时器结束后再执行then
then支持链式调用,下一次then执行受上一次then返回值的影响
定时器问题
在下面这个例子中,一秒之后状态才更新
1 2 3 4 5 6 7 8 9
| const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject("失败"); }, 1000); }).then( (res) => console.log(res), (err) => console.log(err) );
|
可以先把then里的两个回调保存起来,然后等到 1 秒过后,执行resolve或者reject,再去判断状态,并判断要去执行刚刚保存的两个回调中的哪一个回调。

只要状态是pending,那就证明定时器还没跑完,因为如果定时器跑完的话,那状态肯定就不是pending,而是fulfilled/rejected。
可以使用数组来保存回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| initValue() { this.PromiseResult = null this.PromiseState = 'pending' + this.onFulfilledCallbacks = [] + this.onRejectedCallbacks = [] }
resolve(value) { if (this.PromiseState !== 'pending') return this.PromiseState = 'fulfilled' this.PromiseResult = value + while (this.onFulfilledCallbacks.length) { + this.onFulfilledCallbacks.shift()(this.PromiseResult) + } }
reject(reason) { if (this.PromiseState !== 'pending') return this.PromiseState = 'rejected' this.PromiseResult = reason + while (this.onRejectedCallbacks.length) { + this.onRejectedCallbacks.shift()(this.PromiseResult) + } }
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
if (this.PromiseState === 'fulfilled') { onFulfilled(this.PromiseResult) } else if (this.PromiseState === 'rejected') { onRejected(this.PromiseResult) **+ } else if (this.PromiseState === 'pending') { + + this.onFulfilledCallbacks.push(onFulfilled.bind(this)) + this.onRejectedCallbacks.push(onRejected.bind(this))** + }
}
|
链式调用
then支持链式调用,下一次then执行受上一次then返回值的影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const p3 = new Promise((resolve, reject) => { resolve(100); }) .then( (res) => 2 * res, (err) => console.log(err) ) .then( (res) => console.log(res), (err) => console.log(err) );
const p4 = new Promise((resolve, reject) => { resolve(100); }) .then( (res) => new Promise((resolve, reject) => resolve(3 * res)), (err) => console.log(err) ) .then( (res) => console.log(res), (err) => console.log(err) );
|
then方法本身会返回一个新的Promise对象
- 如果返回值是
promise对象,返回值为成功,新promise就是成功
- 如果返回值是
promise对象,返回值为失败,新promise就是失败
- 如果返回值非
promise对象,新promise对象就是成功,值为此返回值
因此,then执行后返回一个Promise对象,就能保证then完还能继续执行then。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
var thenPromise = new MyPromise((resolve, reject) => {
const resolvePromise = cb => { try { const x = cb(this.PromiseResult) if (x === thenPromise) { throw new Error('不能返回自身。。。') } if (x instanceof MyPromise) { x.then(resolve, reject) } else { resolve(x) } } catch (err) { reject(err) } }
if (this.PromiseState === 'fulfilled') { resolvePromise(onFulfilled) } else if (this.PromiseState === 'rejected') { resolvePromise(onRejected) } else if (this.PromiseState === 'pending') { this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled)) this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected)) } })
return thenPromise
}
|
微任务
then方法是微任务,使用定时器,让resolvePromise函数异步执行,模拟微任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const resolvePromise = (cb) => { setTimeout(() => { try { const x = cb(this.PromiseResult); if (x === thenPromise) { throw new Error("不能返回自身。。。"); } if (x instanceof MyPromise) { x.then(resolve, reject); } else { resolve(x); } } catch (err) { reject(err); } }); };
|
其他方法
all
- 接收一个
Promise数组,数组中如有非Promise项,则此项当做成功
- 如果所有
Promise都成功,则返回成功结果数组
- 如果有一个
Promise失败,则返回这个失败结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| static all(promises) { const result = [] let count = 0 return new MyPromise((resolve, reject) => { const addData = (index, value) => { result[index] = value count++ if (count === promises.length) resolve(result) } promises.forEach((promise, index) => { if (promise instanceof MyPromise) { promise.then(res => { addData(index, res) }, err => reject(err)) } else { addData(index, promise) } }) }) }
|
race
- 接收一个
Promise数组,数组中如有非Promise项,则此项当做成功
- 哪个
Promise最快得到结果,就返回那个结果,无论成功失败
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| static race(promises) { return new MyPromise((resolve, reject) => { promises.forEach(promise => { if (promise instanceof MyPromise) { promise.then(res => { resolve(res) }, err => { reject(err) }) } else { resolve(promise) } }) }) }
|
allSettled
- 接收一个
Promise数组,数组中如有非Promise项,则此项当做成功
- 把每一个
Promise的结果,集合成数组,返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| static allSettled(promises) { return new Promise((resolve, reject) => { const res = [] let count = 0 const addData = (status, value, i) => { res[i] = { status, value } count++ if (count === promises.length) { resolve(res) } } promises.forEach((promise, i) => { if (promise instanceof MyPromise) { promise.then(res => { addData('fulfilled', res, i) }, err => { addData('rejected', err, i) }) } else { addData('fulfilled', promise, i) } }) }) }
|
any
- 接收一个 Promise 数组,数组中如有非 Promise 项,则此项当做成功
- 如果有一个 Promise 成功,则返回这个成功结果
- 如果所有 Promise 都失败,则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| static any(promises) { return new Promise((resolve, reject) => { let count = 0 promises.forEach((promise) => { promise.then(val => { resolve(val) }, err => { count++ if (count === promises.length) { reject(new AggregateError('All promises were rejected')) } }) }) }) } }
|
retry
- 如果可以用 async await 的话,那么可以用 while 循环,通过同步的语法实现
- 如果不能用 async await 的话,那么可以用 Promise 递归调用的方法实现
如果要求两次请求间隔一段时间,用 promise 会更方便
在外层使用 async
1 2 3 4 5 6 7 8 9 10 11 12
| Promise.retry = async function (fn, times = 3) { while (true) { console.log(times); times--; try { const res = await fn(); return res; } catch (error) { if (times === 0) throw error; } } };
|
在内层使用 async
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Promise.retry = function (promiseFn, times = 3) { return new Promise(async (resolve, reject) => { while (true) { console.log(times); times--; try { var ret = await promiseFn(); resolve(ret); break; } catch (error) { if (times === 0) { reject(error); break; } } } }); };
|
使用 promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Promise.retry = function (fn, times = 3) { return new Promise(function (resolve, reject) { function retry() { console.log(times); times--; fn() .then(resolve) .catch((error) => { if (times === 0) { reject(error); } else { retry(); } }); } retry(); }); };
|
参考资料
- 看了就会,手写 Promise 原理,最通俗易懂的版本