promise我们都比较熟悉,我们经常用于异步处理,接下来我们一起用简单明了的方法,手写promise。
基本代码
const p1 = new Promise((resolve, reject)=>{
})
const p2 = new Promise((resolve, reject)=>{
resolve('成功')
reject('失败')
})
const p3 = new Promise((resolve, reject)=>{
reject('失败')
})
console.log(p1) // Promise {<pending>}
console.log(p2) // Promise {<fulfilled>: '成功'}
console.log(p3) // Promise {<rejected>: '失败'}
从上面的代码我们可以分析出几个简单的结论:
- Promise 是一个类
- 在执行这个类的时候,在构造函数里面传递一个执行器进去,并立即执行.
- Promise中有三种状态, 分别为pendding(等待)、fulfilled(成功)、rejected(失败)
- pending --> fulfilled
- pending --> rejected 状态只能从pending 变更为 fulfilled 或 rejected,且一旦状态确定下来就不可变更。
- 执行器接收接收两个参数resolve和reject,这两个参数是两个函数,用来变更状态的
- resolve: fulfilled
- reject: rejected
从上面的结论,设计代码如下:
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise{
constructor(excutor){
excutor(this._resolve,this._reject)
}
// promise 状态
status = PENDING
// 更改状态的 resolve 方法
// 这里用箭头函数,否则要绑定 this,使this的指向永远指向当前的 MyPromise
_resolve = () => {
// 判断状态是否为等待,否则阻止执行
if(status === PENDING) return;
// 更改为成功状态
this.status = FULFILLED
}
// 更改失败的状态 reject 方法
// 这里用箭头函数,否则要绑定 this,使this的指向永远指向当前的 MyPromise
_reject = reason => {
// 判断状态是否为等待,否则阻止执行
if (this.status !== PEDDING) return
// 改变为失败状态
this.status = REJECTED
}
}
new MyPromise((resolve, reject) => {
resolve('') // status--> fulfilled
})
then 方法
我们先看看then方法的调用
// 立即输出成功
const p1 = new Promise((resolve, reject) => {
resolve('成功')
}).then(res => console.log(res), err => console.log(err))
// 输出
p1.then(res => console.log(res))
// 一秒后输出失败
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
},1000)
}).then(res => console.log(res), err => console.log(err))
// 输出5
const p3 = new Promise((resolve, reject) => {
resolve(2)
}).then((res) => res + 3).then(res => console.log(res))
从 p1 和 p2 分析可以得出: 1. then方法有两个回调方法,如果是成功状态就调用成功回调,如果是失败状态就调用失败回调的方法。2.then 成功回调有一个参数,返回成功的值。失败回调有一个参数,返回失败的原因。代码如下:
class MyPromise{
constructor(excutor){
excutor(this._resolve,this._reject)
}
// promise 状态
status = PENDING
// 成功的值
value = undefined
// 失败的原因
reason = undefined
// 成功的回调
successCallback = undefined
// 失败的回调
failCallback = undefined
// 更改状态的 resolve 方法
// 这里用箭头函数,否则要绑定 this,使this的指向永远指向当前的 MyPromise
_resolve = value => {
// 判断状态是否为等待,否则阻止执行
if(status === PENDING) return;
// 更改为成功状态
this.status = FULFILLED
// 保存成功的值
this.value = value
}
// 更改失败的状态 reject 方法
// 这里用箭头函数,否则要绑定 this,使this的指向永远指向当前的 MyPromise
_reject = reason => {
// 判断状态是否为等待,否则阻止执行
if (this.status !== PEDDING) return
// 改变为失败状态
this.status = REJECTED
// 保存失败的原因
this.reason = reason
}
// then
then(successCallback, failCallback){
if(this.status === FULFILLED){ // 成功执行成功回调
successCallback(this.value)
}else if(this.status === REJECTED){ // 失败执行失败回调
failCallback(this.reason)
}
}
}
分析p2,p3 还可以得出:3.then方法参数是可选的 4.如果resolve和reject中有异步代码时,异步代码执行完再调回调
then(successCallback, failCallback){
// 参数可选
successCallback = successCallback ? successCallback : value => value
// 失败参数可选
failCallback = failCallback ? failCallback : reason => { throw reason }
if(this.status === FULFILLED){ // 成功执行成功回调
successCallback(this.value)
}else if(this.status === REJECTED){ // 失败执行失败回调
failCallback(this.reason)
}else {
// 保存回调方法 成功或失败时调用
this.successCallback = successCallback
this.failCallback = failCallback
}
}
_resolve = value => {
// 判断状态是否为等待,否则阻止执行
if(status === PENDING) return;
// 更改为成功状态
this.status = FULFILLED
// 保存成功的值
this.value = value
// 有成功回调就调回调
this.successCallback && this.successCallback()
}
_reject = reason => {
// 判断状态是否为等待,否则阻止执行
if (this.status !== PEDDING) return
// 改变为失败状态
this.status = REJECTED
// 保存失败的原因
this.reason = reason
// 有失败回调就调回调
this.failCallback && this.failCallback()
}
p1 中的同个promise的then 方法是可以多次调用的,将我们的代码更改如下
// 把成功和失败的回调的初始值更改为数组
- successCallback = undefined
- failCallback = undefined
+ successCallback = []
+ failCallback = []
_resolve= value => {
...
- this.successCallback && this.successCallback()
+ while(this.successCallback.length)this.successCallback.shift()(this.value)
}
_reject = reason => {
...
- this.failCallback && this.failCallback()
+ while(this.failCallback.length)this.failCallback.shift()(this.reason)
}
then 方法修改如下:
then(successCallback, failCallback){
successCallback = successCallback ? successCallback : value => value
// 失败参数可选
failCallback = failCallback ? failCallback : reason => { throw reason }
if(this.status === FULFILLED){ // 成功执行成功回调
successCallback(this.value)
}else if(this.status === REJECTED){ // 失败执行失败回调
failCallback(this.reason)
}else {
// 保存回调方法 成功或失败时调用
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
分析p3:5.then 方法是可以链式调用的,then是promise的原型链的方法,所以then 方法要返回一个promise的对象. 6.上一个then方法的返回值是可以传递给下一个then方法的 7. 判断回调函数的值是普通值还是promise对象,如果是普通值直接resolve 如果是promise对象,根据返回结果调用resolve 或 reject,且循环调用时报错,抽成relovePromise 方法 。promise是微任务 此处只是用setTimeout简单模拟。
resolvePromise 方法:
function resolvePromise(promise2, x, resolve, reject){
// 如果返回的promise对象是本身报错
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise){
x.then(resolve, reject)
} else{
resolve(x)
}
}
then 方法更改如下:
then(successCallback, failCallback){
successCallback = successCallback ? successCallback : value => value
// 失败参数可选
failCallback = failCallback ? failCallback : reason => { throw reason }
const promise2 = new MyPromise((resolve, reject) => {
if(this.status === FULFILLED){ // 成功执行成功回调
setTimeout(() => {
try {
let x = successCallback(this.value)
// 判断x 的值是否为promise对象,如果是则根据返回值调用resolve和reject
// 普通值直接resolve
resolvePromise(proimse2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}else if(this.status === REJECTED){ // 失败执行失败回调
setTimeout(() => {
try {
let x = failCallback(this.reason)
// 判断x 的值是否为promise对象,如果是则根据返回值调用resolve和reject
// 普通值直接resolve
resolvePromise(proimse2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}else {
// 保存回调方法 成功或失败时调用
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
// 判断x 的值是否为promise对象,如果是则根据返回值调用resolve和reject
// 普通值直接resolve
resolvePromise(proimse2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason)
// 判断x 的值是否为promise对象,如果是则根据返回值调用resolve和reject
// 普通值直接resolve
resolvePromise(proimse2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
catch 方法
catch 实际是 then 方法的变形
catch (failCallback) {
return this.then(undefined, failCallback)
}
finally 方法
finally (callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
静态方法
1. resolve
static resolve (value) {
// 如果是promise 直接返回
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value))
}
2. reject
static reject (reason) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve, reject) => reject(reason))
}
3. all
- all 方法是解决异步方法调用的顺序问题的,允许按我们调用的顺序返回
- 接收一个数组作为参数,如果是普通值直接添加到resolve,判断promise对象根据结果处理
- 返回值是一个promise对象
- 所有promise成功了才是成功,有一个promise是reject都是返回这个值
static all (array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData (key, value) {
result[key] = value
index++;
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) {
// pomise
current.then(value => addData(i, value), reason => reject(reason))
} else {
// 普通值
addData(i, current)
}
}
})
}
4. allSettle
- 接收一个数组,如果数组中有非rpomise的项直接resolve
- 将每项peomise的结果的数组,返回
static all (array) {
let result = [];
let index = 0;
return new MyPromise((resolve, reject) => {
function addData (key, status, value) {
result[key] = {
status,
value
}
index++;
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) {
// pomise
current.then(value => addData(i,FULFILLED,value), reason => addData(i,REJECTED,reason))
} else {
// 普通值
addData(i,FULFILLED,current)
}
}
})
}
5. race
- 接收一个promise数组,如有非promise项直接resolve
- 返回最快的那一个promise的值
static race (array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) {
current.then(res => {
resolve(res)
},
reason => {
reject(reason)
})
} else {
resolve(current)
}
}
})
}
6. any
- any 与 all 相反
- 接收一个promise数组,如有非promise项直接成功
- 如果有一个promise成功,则返回这个成功的结果
- 如果所有的promise都失败,则报错
static any (array) {
return new MyPromise((resolve, reject) => {
let index = 0
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) {
current.then(res => {
resolve(res)
},
reason => {
index++;
if (index === array.length) {
reject(new AggregateError('All promise were rejected'))
}
})
} else {
resolve(current)
}
}
})
}