废话不多说,直接上代码,如果还不清楚promise基础知识的同学请移步这里https://es6.ruanyifeng.com/#docs/promise
/**
* promise常规用法:
* 1、promise 通过 new 关键字调用,说明promise是一个类
* 2、promise有三种状态,pending,fulfilled,rejected,状态只能从pending -> fulfilled 和 pending -> rejected,此过程是单向的,不可逆的
* 3、promise状态的改变通过resolve和reject函数实现,这两个方法定义在原型上
* 4、调用promise的时候会传入一个函数当作参数
* 5、new promise之后生成的对象,可以调用then、finally和catch方法,这些方法定义在原型上
* 6、then方法接收两个回调函数,一个成功回调,一个失败回调
* 7、同一个promise对象可以同时调用多次then方法,因此then方法成功回调和失败回调是两个数组,存储多次调用then方法时传递的函数
* 8、Promise.resolve和Promise.all因为 '.' 的调用方式,因此应该定义为静态方法
*
*/
//将promise状态声明成常量,方便复用
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
/*
* resolvePromise方法的作用是判断then方法接收的回调函数的返回值的类型,
* 如果是普通值,直接调用 resolve(x)将返回值传递给promise2的then方法,
* 如果是promise实例,则求出x的返回值,传递给promise2的then方法
*/
const resolvePromise = (promise2, x, resolve, reject) => {
//promise2和x不能是同一个对象,是的话报错
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #' ))
}
//如果x是一个MyPromise的实例
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {//x是一个普通值
resolve(x)
}
}
class MyPromise {
//调用new MyPromise时传入一个执行器函数,该执行器函数立即执行,并且执行器函数接收两个更改状态的函数,resolve和reject
constructor (executor) {
this.status = PENDING //状态初始化为pending
this.value = undefined //成功返回值
this.reason = undefined //失败返回值
this.onResolvedCallback = [] //成功的回调队列
this.onRejectedCallback = [] //失败的回调队列
//箭头函数是为了在定义时绑定词法作用域中的this
let resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
//成功执行回调
if (this.onResolvedCallback.length) {
this.onResolvedCallback.forEach(fn => fn())
}
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
//失败执行回调
if (this.onRejectedCallback.length) {
this.onRejectedCallback.forEach(fn => fn())
}
}
}
//try catch是为了捕获调用new Promise()时抛出的异常
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
//then方法接收两个参数,一个成功回调,一个失败回调
then (successCallback, failCallback) {
// 在实际应用中then方法的成功回调和失败回调参数并不是必传的,当用户没有传参的时候,给参数设一个默认值
successCallback ? successCallback : value => value
failCallback ? failCallback : reason => { throw reason }
let promise2 = new MyPromise((resolve, reject) => {
//将then方法中接受的的回调函数的返回值保存在变量中,以便传递给promise2对象中的then方法
let x
//同步逻辑,成功回调
if (this.status === FULFILLED) {
//setTimeout方法将同步代码修改为异步代码,这样才能获取到promise2
setTimeout(() => {
//在这里用try catch是为了捕获then方法中抛出的异常
try {
x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
//同步逻辑,失败回调
if (this.status === REJECTED) {
setTimeout(() => {
try {
x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
//异步逻辑
if (this.status === PENDING) {
//由于调用new promise时传入的执行器函数里异步操作,此时还没有返回结果,因此需要将回调函数暂存进回调队列中
this.onResolvedCallback.push(() => {
setTimeout(() => {
try {
x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.onRejectedCallback.push(() => {
setTimeout(() => {
try {
x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
//由于then可以链式调用,因此then方法返回一个promise对象
return promise2
}
/**
* 无论promise的状态是什么,都会执行finally方法,调用finally方法之后可以继续调用then方法,
* 因此finally方法返回的是promise对象
*/
finally (cb) {
return this.then(value => {
return MyPromise.resolve(cb()).then(() => value)
}, reason => {
return MyPromise.resolve(cb()).then(() => { throw reason })
})
}
/**
* promise的then方法可以不传递失败回调函数,失败原因可以一直传递下去,最终可以被catch捕获到
* 在catch方法中的内部调用then方法,只传递失败回调方法即可
*/
catch (failCallback) {
return this.then(null, failCallback)
}
/**
* all方法接收一个数组,该数组中的元素可以是MyPromise的实例,也可以是一个普通值
* all方法之后可以继续调用then方法,因此then方法返回一个MyPromise实例对象
* 判断数组中的每一个元素类型,普通值直接存入result数组中,如果是MyPromise实例
* 则执行then方法,将结果存进result中,当传入的所有结果都得到的时候调用resolve方法
* 改变状态
*
*/
static all (array) {
let result = [], index = 0
return new MyPromise((resolve, reject) => {
function addData (key, value) {
result[key] = value
index++
if (index == array.length) {
resolve(result)
}
}
array.forEach((item, i) => {
if (item instanceof MyPromise) {
item.then(value => addData(i, value), reason => reject(reason))
} else {
addData(i, item)
}
})
})
}
/**
* race方法接收一个数组,该数组中的元素可以是MyPromise的实例,也可以是一个普通值
* race方法之后可以继续调用then方法,因此then方法返回一个MyPromise实例对象
* race方法中接收的参数只要有一个返回结果,MyPromise的状态就更改,结束运行
*/
static race (array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
if (array[i] instanceof MyPromise) {
array[i].then(resolve, reject)
} else {
resolve(array[i])
}
}
})
}
/**
* resolve方法可以把一个传入的参数包装成MyPromise对象
* resolve方法接收一个参数,如果该参数是一个MyPromise对象,则返回它本身,
* 如果是一个普通值,则将该值用MyPromise包装返回
*/
static resolve (value) {
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
}