手写Promise
-
Promise为一个类,初始化时将为其传入一个执行器,该执行器会立即执行。执行器接收两个参数:Promise内部resolve和reject方法
-
Promise有三个状态:Pending、Fulfilled、Rejected,状态只能由Pending->Fulfilled或Pending->Rejected,状态一旦变更就固定了,无法再次改变
-
Promise使用内部resolve和reject方法更改Promise状态。在调用时除了更改状态外,还会去判断是否缓存了成功或失败的回调函数,若存在则按顺序执行对应的回调函数
-
then方法
then方法接收两个参数,成功回调和失败回调。调用then方法时,会去判断当前实例的状态,若状态为Fulfilled则调用成功回调,若状态为失败则调用失败回调,若状态为Pending则将两个回调函数缓存下来,等待resolve或reject时调用
同一个实例的then方法可以被多次调用
then方法可以链式调用,其回调函数的返回值将传递给下一个then方法。若返回值为普通值,则直接调用resolve将值传递给下一个then的成功回调;若返回值为promise则会根据promise执行后的结果,来决定调用resolve传递值还是调用reject抛出失败原因
为避免then回调函数循环调用,需判断回调函数的返回值是否为then自身promise,若为then自身promise则抛出类型错误异常
then方法的参数是可选的,若不传递,默认成功时返回成功结果,失败时抛出失败原因 -
catch方法
内部调用实例then方法返回一个新的promise对象,then方法中成功回调设为undefined,失败回调设为传入的参数
-
finally方法
finally方法参数接收一个回调函数,返回一个新的promise,无论Promise成功还是失败都会调用该回调函数
因为需要在上一个Promise返回结果后再执行传入的callback,所以需调用实例then方法,在成功和失败的回调中分别调用callback。若callback返回值为promise对象,下一个then方法中的回调函数,将会等待promise执行后再调用。 -
Promise.resolve 静态方法
接收一个参数,若该参数为Promise对象,则直接返回该参数;若为普通值,则返回一个新的Promise对象,并resolve该值
-
Promise.reject 静态方法
接收一个参数,返回一个新的Promise对象,并reject该值
-
Promise.all 静态方法
接收一个参数返回一个新的Promise对象,该参数为一个数组,all方法将会等待数组中全部成员成功的结果返回后,统一返回包含对应结果的结果数组。
若其中一个成员的返回结果为失败,则立即抛出该失败原因 -
Promise.race 静态方法
接收一个参数返回一个新的Promise对象,该参数为一个数组,race方法将会等待数组成员中最先返回的结果,将其结果作为自己Promise的值。
const PENDING = 'Pending'
const FULFILLED = 'Fulfilled'
const REJECTED = 'Rejected'
class MyPromise {
// 构造函数,接收一个执行器
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
// 状态值
status = PENDING
// 成功的结果
value = undefined
// 失败的原因
reason = undefined
// 成功回调
successCallback = []
// 失败回调
failCallback = []
// resolve和reject方法是在执行器内直接调用的,普通函数直接调用,this指向window或undefined,为保证内部this指向MyPromise实例对象,需使用箭头函数。若使用普通函数,需在构造器函数中给executor传参时绑定this(executor(this.resolve.bind(this),this.reject.bind(this)))
resolve = (value) => {
// 状态只能由pending->fulfilled或pending->rejected,且一旦变更状态就凝固了,重复调用resolve/reject也无法再次修改
if (this.status === PENDING) {
// 状态改为成功
this.status = FULFILLED
// 保存成功结果
this.value = value
// 判断是否存在成功回调函数
while (this.successCallback.length) this.successCallback.shift()()
}
}
// resolve和reject方法是在执行器内直接调用的,普通函数直接调用,this指向window或undefined,为保证内部this指向MyPromise实例对象,需使用箭头函数。若使用普通函数,需在构造器函数中给executor传参时绑定this(executor(this.resolve.bind(this),this.reject.bind(this)))
reject = (reason) => {
// 状态只能由pending->fulfilled或pending->rejected,且一旦变更状态就凝固了,重复调用resolve/reject也无法再次修改
if (this.status === PENDING) {
// 状态改为失败
this.status = REJECTED
// 保存成功结果
this.reason = reason
// 判断是否存在失败回调函数
while (this.failCallback.length) this.failCallback.shift()()
}
}
//then方法为实例调用无this指向问题(p1.then()),且所有实例都能调用该方法,应将其定义在原型对象上
then(successCallback, failCallback) {
// then方法参数为可选值
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => {
throw reason
};
let thenPromise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
try {
// 通过异步,让同步代码先执行,以获取thenPromise
setTimeout(() => {
// 成功
let result = successCallback(this.value)
// 判断回调函数结果是否为Promise对象,是否为thenPromise本身
resolvePromise(thenPromise, result, resolve, reject)
}, 0)
} catch (e) {
reject(e)
}
} else if (this.status === REJECTED) {
try {
setTimeout(() => {
// 失败
let reason = failCallback(this.reason)
// 判断回调函数结果是否为Promise对象,是否为thenPromise本身
resolvePromise(thenPromise, reason, resolve, reject)
}, 0)
} catch (e) {
reject(e)
}
} else {
// 等待
// 保存成功或失败回调函数,等待resolve或reject调用时执行
this.successCallback.push(() => {
try {
setTimeout(() => {
// 成功
let result = successCallback(this.value)
// 判断回调函数结果是否为Promise对象,是否为thenPromise本身
resolvePromise(thenPromise, result, resolve, reject)
}, 0)
} catch (e) {
reject(e)
}
})
this.failCallback.push(() => {
try {
setTimeout(() => {
// 失败
let reason = failCallback(this.reason)
// 判断回调函数结果是否为Promise对象,是否为thenPromise本身
resolvePromise(thenPromise, reason, resolve, reject)
}, 0)
} catch (e) {
reject(e)
}
})
}
})
return thenPromise;
}
// catch方法 接收一个失败回调函数
catch (failCallback) {
return this.then(undefined, failCallback)
}
// finally方法 返回一个promise,无论成功失败都会调用callback,且finally后续then中的回调会等待callback执行完毕再执行。
finally(callback) {
return this.then(value => {
// 此处需注意,将then的成功回调返回上面的value值,而不是返回自身的返回值,所以需定义成功回调() => value。失败回调未定义,then内部会自动赋值reason=>{throw reason}抛出自身异常。
MyPromise.resolve(callback()).then(() => value)
}, reason => {
// 此处需注意,将then的成功回调抛出上面的reason异常,而不是返回自身的返回值,所以需定义成功回调() => {throw reason}。失败回调未定义,then内部会自动赋值reason=>{throw reason}抛出自身异常。
MyPromise.resolve(callback()).then(() => {
throw reason
})
})
}
// MyPromise.resolve
static resolve(value) {
// 判断是否为promise对象
// 参数为Promise对象,直接返回
if (value instanceof MyPromise) return value;
// 参数非Promise对象,返回new MyPromise
return new MyPromise(resolve => resolve(value))
}
// MyPromise.reject
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
// MyPromise.all 按照异步API调用顺序得到异步API的执行结果,得到所有成员成功结果后一并返回,若失败则立即返回该成员的失败原因
static all(array) {
let result = []
let index = 0
return new MyPromise((resolve, reject) => {
// 声明添加方法
function addData(key, value) {
result[key] = value
index++
// 此处不能写result.length === array.length,因为result[n]=value时,result的长度已经是n了
if (index === array.length)
resolve(result)
}
// 遍历参数数组
for (let i = 0; i < array.length; i++) {
const item = array[i];
// 判断是否为promise对象
if (item instanceof MyPromise) {
// promise对象 在回调函数中向result添加返回结果
item.then(value => addData(i, value), reason => reject(reason))
} else {
// 普通值
addData(i, item)
}
}
})
}
// MyPromise.race 等待数组成员中最先返回的结果,将其结果作为自己返回的Promise的值
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
const item = array[i];
if (item instanceof MyPromise) {
item.then(resolve, reject)
} else {
resolve(item)
}
}
})
}
}
// 判断successRes是普通值还是promise对象
// 如果是普通值,直接调用resolve返回结果。
// 如果是promise对象,需判断其状态。如果是Fulfilled,调用resolve;如果是Rejected,调用reject。
// 判断回调函数返回结果是否为thenPromise本身,避免循环调用
function resolvePromise(thenPromise, result, resolve, reject) {
// 判断是否返回自身
if (result === thenPromise) {
return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>]'))
}
if (result instanceof MyPromise) {
// promise对象
result.then(resolve, reject)
} else {
// 普通值
resolve(result)
}
}
module.exports = MyPromise