一、准备工作
要实现promise,先看看promise是什么、做了哪些。
Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值,有以下两个特点:
1、对象的状态不受外界影响。
Promise 对象代表一个异步操作,有三种状态:
pending: 初始状态,不是成功或失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。
一个promise基本的代码功能大致如下,需要接收函数运行处理,提供resolve、reject方法并返回操作成功/失败的结果。
new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(222);
},2000)
}).then(res => {
console.log('res',res);
});
需要哪些必要元素实现这些功能?
接收运行函数,
提供resolve、reject方法保存成功、失败的结果
then方法抛出res、err信息
res、err存储变量
保存成功、失败的变量,以此为判断依据抛出res、err
二、代码实现
1、先写下大致框架
const PENDDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MyPromise {
constructor(callback) {
this.status = PENDDING
this.succ_data = undefined
this.err_data = undefined
callback(resolve,reject)
}
resolve(val) {
}
reject(err) {
}
then(onFulFilled, onRejected) {
}
}
2、完善、验证一下
1>. 回调函数为匿名函数时,回调函数的this会指向window,需要对回调函数bind(this)。
2>. 回调函数为箭头函数时,回调函数的this会指向他的直接上层,本例中指向obj,objx。
const PENDDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MyPromise {
constructor(callBack) {
this.status = PENDDING
this.succ_data = undefined
this.err_data = undefined
this.then = this.then.bind(this) //绑定下this指向, 类比较特殊
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
try{
callBack(this.resolve, this.reject)
}catch(err){
this.reject(err)
}
}
resolve(val) {
if (this.status !== PENDDING) { //状态只能从PENDDING而来
return false
}
this.succ_data = val //存储成功数据
this.status = FULFILLED // 改变状态,处理ok
}
reject(err) {
if (this.status !== PENDDING) { //状态只能从PENDDING而来
return false
}
this.err_data = err //存储失败数据
this.status = REJECTED // 改变状态,处理ok
}
then(onFulFilled, onRejected ){
if(this.status === FULFILLED){
onFulFilled(this.succ_data)
}
if(this.status === REJECTED){
onRejected(this.err_data)
}
}
}
会发现并未如期望的打印出res,这是因为then方法时,resolve还未执行,此时的succ_data还是undefined
解决:暂存then任务至数组,当status改变时继续执行
3、添加队列相关代码
then(onFulFilled, onRejected ){
if(this.status === FULFILLED){
onFulFilled(this.succ_data)
}else if(this.status === REJECTED){
onRejected(this.err_data)
}else{
this.queue.push({resolve:onFulFilled,reject:onRejected}) //实际是将then的功能在resolve阶段完成
}
}
resolve(val) {
if (this.status !== PENDDING) { //状态只能从PENDDING而来
return false
}
this.succ_data = val //存储成功数据
this.status = FULFILLED // 改变状态,处理ok
if( this.queue.length > 0 ){
this.queue.map((item,index)=>{
item.resolve(val)
})
}
}
reject(err) {
if (this.status !== PENDDING) { //状态只能从PENDDING而来
return false
}
this.err_data = err //存储失败数据
this.status = REJECTED // 改变状态,处理ok
if( this.queue.length > 0 ){
this.queue.map((item,index)=>{
item.resolve(err)
})
}
}
4、链式调用
原生的 Promise
对象的then方法,返回的也是一个 Promise
对象,一个新的 Promise
对象,这样才可以支持链式调用,一直then
下去。。。 而且,then
方法可以接收到上一个then
方法处理return的结果。根据Promise
的特性分析,这个返回结果有3种可能:
MyPromise
对象;- 具有
then
方法的对象; - 其他值。 根据这三种情况分别处理。
- 第一个处理的是,
then
方法返回一个MyPromise
对象,它的回调函数接收resFn
和rejFn
两个回调函数; - 把成功状态的处理代码封装为
handleFulfilled
函数,接受成功的结果作为参数; handleFulfilled
函数中,根据onFulfilled
返回值的不同,做不同的处理:- 首先,先获取
onFulfilled
的返回值(如果有),保存为returnVal
; - 然后,判断
returnVal
是否有then方法,即包括上面讨论的1、2中情况(它是MyPromise
对象,或者具有then
方法的其他对象),对我们来说都是一样的; - 之后,如果有
then
方法,马上调用其then
方法,分别把成功、失败的结果丢给新MyPromise
对象的回调函数;没有则结果传给resFn
回调函数。
- 首先,先获取
then(onFullFiled, onRejected){
const _this = this
return new MyPromise((resFn,rejFn)=>{
switch(this.status){
case PEDDING:
this.queue.push({
resolve:onFullFIled,
handleRej:onRejected
})
break;
case RESOLVED:
console.log('this.success_data', this.success_data)
handleRes(this.success_data)
break;
case REJECTED:
handleRej(this.error_data)
break;
}
function handleRes(val){
let returnVal = onFullFiled instanceof Function && onFullFiled(val) || val //获取码农返回的promise
console.log('returnVal',returnVal)
if(returnVal['then'] && returnVal['then'] instanceof Function){
returnVal.then(res=>{ //获取码农希望的resolve/reject的值,并resolve/reject
resFn(res)
// console.log('resFn(res)',res)
},err=>{
rejFn(err)
})
}else{
resFn(val)
}
}
function handleRej(val){
let returnVal = onRejected instanceof Function && onRejected(val) || val //获取码农返回的promise
if(returnVal['then'] && returnVal['then'] instanceof Function){
returnVal.then(res=>{ //获取码农希望的resolve/reject的值,并resolve/reject
resFn(res)
},err=>{
rejFn(err)
})
}else{
rejFn(val)
}
}
})
}