1.了解Promise
众所周知,Promise是JS中异步编程的一种解决方案。
在模拟实现Promise之前,首先需要了解Promise的特性。
1.一个promise(Promise的实例),有三种状态,初始时的等待态pending,成功时的成功态resolved以及失败态rejected。promise的状态只能被改变一次,只能从pending成为resolved或者rejected,改变不可逆。
2.promise改变状态的方式有三种,当调用resolve时,由pending变为resolved,当调用reject,或者执行器函数内部抛出异常时,由pending变为rejected。
3.对同一个promise指定了多个回调函数时,当promise变为对应状态时,对应的回调函数全部都会执行。
4.p.then() 返回的Promise的结果状态怎么确定?
由then指定的回调函数的结果决定
①如果抛出异常,新的promise变成rejected
②如果回调函数返回的是不是Promise的任意值string,undefined等等,新的promise变为fulfilled,数据是返回的值
③如果回调函数返回的是一个promise对象。返回值promise对象的结果和状态就是新的promise的结果和状态
5.promise异常穿透:在之前的then中只写了一个成功的回调,没有写失败的回调 相当于隐式的写了 err=>{throw err} 所以会穿透
①当使用promise的then链式调用时,可以在最后指定失败的回调
②前面的任何操作出现了异常都会传到最后的失败的回调函数中处理
6.中断promise链:当使用promise链式调用时,在中间中断,不再调用后面的回调函数
方法:在需要中断处 返回一个pending状态的promise return new Promise(()={})
2.Promise的模拟实现
实现Promise中的then、catch、all、race、resolve、reject方法。
使用的时ES6语法。
1.MyPromise整体结构
class MyPromise {
//构造函数 参数是执行器函数
constructor(executor) {
}
//指定成功和失败的回调函数,返回一个新的promise
then(resolvedCallBack, rejectedCallBack = error => { throw error }) {
}
//返回一个新的promise
catch(rejectedCallBack) {
}
/**
* @author: forceddd
* @desc: 要判断传入的数组是否全部是promise对象
* @param {Promise[]} promises
* @return: 返回最先完成的promise任务结果和状态 无论成功或者失败
*/
static race(promises) {
}
/**
* @author: forceddd
* @desc: 当所有promise都成功时,返回一个成功态的promise 数据是所有promise成功数据组成的数组 否则返回一个失败态的promise
* @param ArrayOfPromises
* @return: promise
*/
static all(promises) {
}
/**
* @author: forceddd
* @desc: 传入非promise 返回一个成功态的promise data是该参数
* 传入promise 返回值的状态和结果由参数promise的状态和结果决定
* @param {any} data
* @return: 返回一个指定结果的promise
*/
static resolve(data) {
}
/**
* @author: forceddd
* @desc: 不考虑传入promise
* @param {any} error 拒绝的reason
* @return: 返回一个失败状态的promise 失败原因是传入的参数
*/
static reject(error) {
}
}
2.构造器的实现
//构造函数 参数是执行器函数(执行器函数是同步执行的)
constructor(executor) {
this.status = 'pending';//当前实例的状态
this.data = undefined;//用于存储完成后的数据
this.callBacks = [];//用于存储promise完成之前,即状态仍为pending时,便指定的回调函数 [{resolveCb,rejectCb}]
//箭头函数让this指向构造函数中的this 即实例 否则resolve和reject中的this会指向window
//声明两个用于改变promise状态的函数,并且要作为参数传入执行器函数executor中
const resolve = data => {
//status只能被修改一次 判断当前是否是初始值pending
if (this.status !== 'pending') return;
//改变promise状态为成功态
this.status = 'resolved';
//存储成功值
this.data = data;
//如果此时有的回调函数已经被指定了 应当立即--异步地--执行这些回调函数
//通过setTimeout将成功的回调函数放入异步队列
if (this.callBacks.length) {
setTimeout(() => {
this.callBacks.forEach(cbObj => cbObj.resolvedCallBack(data))
})
}
}
const reject = error => {
//status只能被修改一次 判断当前是否是初始值pending
if (this.status !== 'pending') return;
//改变promise状态为失败态
this.status = 'rejected';
//存储失败信息
this.data = error;
//如果此时有的回调函数已经被指定了 应当立即--异步--执行这些回调函数
//通过setTimeout将失败地回调函数放入异步队列
if (this.callBacks.length) {
setTimeout(() => {
this.callBacks.forEach(cbObj => cbObj.rejectedCallBack(error))
})
}
}
// 同步执行executor try catch用于捕获executor抛出的异常
try {
executor(resolve, reject)
} catch (error) {
//如果抛出了异常,promise要变为rejected
reject(error)
}
}
3.then的实现
//指定成功和失败的回调函数,返回一个新的promise
//给rejectedCallBack默认值 实现异常穿透处理 即不传入rejectedCallBack,
//但又是失败态时,会执行默认函数,抛出异常,将then返回值promise转为失败态
then(resolvedCallBack, rejectedCallBack = error => { throw error }) {
//因为在catch中 resolvedCallBack我会传入一个null 所以此处增加一个判断条件
resolvedCallBack = typeof resolvedCallBack === 'function' ? resolvedCallBack : _ => _;
//then的返回值是一个promise
return new MyPromise((resolve, reject) => {
/**
* @desc: 处理then的返回值
* @ 1.如果执行回调函数时抛出了异常 返回一个失败的promise error是异常信息
* @ 2.如果回调函数返回值不是promise对象 ,返回一个成功的promise data是回调函数返回值
* @ 3.如果回调函数的返回值是一个promise 这个promise的状态和结果作为返回值promise的状态和结果
* @param: cb
* @return:
*/
const handleReturn = cb => {
let res;//接收成功或者失败的回调函数的返回值
try {
res = cb(this.data);
res instanceof MyPromise
//3.如果回调函数的返回值是一个promise 这个promise的状态和结果作为返回值promise的状态和结果
? res.then(
data => resolve(data),
error => reject(error)
)
//简写形式 成功时 将resolve作为回调函数resolvedCallBack传入 内部会执行 resolvedCallBack(this.data),
//和传入一个data => resolve(data)效果相同
// res.then(resolve, reject)
//2.如果回调函数返回值不是promise对象 ,返回一个成功的promise data是回调函数返回值
: resolve(res)
} catch (error) {
//1.如果执行回调函数时抛出了异常 返回一个失败的promise error是异常信息
reject(error)
}
}
if (this.status === 'pending') {
//此时实例仍然时pending态 回调函数已经被声明了 将指定的回调函数存储到callBacks中
//此时同样要根据回调函数返回值来判断then的返回值 所以不能直接像下面一样存储回调函数,需要外包一层函数,以便对返回值进行判断
// this.callBacks.push({ resolvedCallBack, rejectedCallBack })
this.callBacks.push({
resolvedCallBack: _ => handleReturn(resolvedCallBack),
rejectedCallBack:_ => handleReturn(rejectedCallBack)
})
/* 在状态改变之后 指定的回调函数 会立即--异步--执行 */
} else if (this.status === 'resolved') {
setTimeout(() => handleReturn(resolvedCallBack));
} else {
setTimeout(() => handleReturn(rejectedCallBack));
}
})
}
4.catch的实现
//返回一个新的promise catch是then的一个语法糖
catch(rejectedCallBack) {
return this.then(null, rejectedCallBack)
}
5.resolve和reject的实现
/**
* @author: forceddd
* @desc: 传入非promise 返回一个成功态的promise data是该参数
* 传入promise 返回这个promise
* @param {any} data
* @return: 返回一个指定结果的promise
*/
static resolve(data) {
return data instanceof MyPromise
? data
: new MyPromise((resolve) => {
resolve(data);
});
}
/**
* @author: forceddd
* @desc: 不考虑传入promise
* @param {any} reason
* @return: 返回一个失败状态的promise 失败原因是传入的参数
*/
static reject(error) {
return new MyPromise((_, reject) => reject(error));
}
6.race的实现
/**
* @author: forceddd
* @desc: 要判断传入的数组是否全部是promise对象
* @param {Promise[]} promises
* @return: 返回最先完成的promise任务结果 无论成功或者失败
*/
static race(promises) {
//返回一个promise
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
//判断元素是不是promise 如果不是,通过resolve函数转换成promise
promise = promise instanceof MyPromise ? promise : MyPromise.resolve(promise);
//将最先完成的promise状态和结果 作为race返回值的状态和结果
promise.then(resolve, reject)
})
})
}
7.all的实现
/**
* @author: forceddd
* @desc: 当所有promise都成功时,返回一个成功态的promise 数据是所有promise成功数据组成的数组 否则返回一个失败态的promise
* @param {Promise[]} promises
* @return: promise
*/
static all(promises) {
let resolveCount = 0;//记录执行then中成功回调函数的次数 每执行一次then的回调函数说明有个一个promise已经有了结果
const results = new Array(promises.length)//创建一个长度和promises相同的数组,用来存储成功的data
return new MyPromise((resolve, reject) => {
promises.forEach((promise, index) => {
//将不是promise的元素转换成promise
promise = promise instanceof MyPromise ? promise : MyPromise.resolve(promise);
promise.then(
data => {
results[index] = data;
resolveCount++;
resolveCount === promises.length && resolve(results);
},
reject //将all的返回值变为reject状态
)
})
})
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。