小程序起步

Promise实现及理解

2020-06-16  本文已影响0人  小本YuDL

别让平淡的生活,毁了对未来的向往❤


1.promise的基本结构

promise必须接受一个函数( handle ) 作为参数,这个函数有两个参数:resolve,reject,且这两个参数本身也是函数。

let promise = new Promise((resolve, reject) => {
    resolve('success');  //reject('fail')
});
promise.then((res)=>{
  console.log(res); // 输出:success
},(err)=>{
  console.log(err); // 上面如果执行reject('fail'),这里就输出:fail
});

2.promise的状态和值

(1)promise有三个状态
状态只能由 **Pending--> Fulfilled** 或着 **Pending --> Rejected** 两种状态变更,变更之后状态**锁定**了,就不会再变更了。
(2)promise返回两种状态

resolve 和 reject 函数都可以传入任意类型的值作为实参,表示 Promise 对象成功(Fulfilled)和失败(Rejected)的值。

(3)promise的值

Promise的值是指状态改变时传递给回调函数的值。

promise的参数handle函数,包含 resolve 和 reject 两个参数,它们是两个函数,可以用于改变 Promise 的状态和传入 Promise 的值。

(a) . resolve 传入的 ‘success’ ,就是 promise 的值。

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 1000)
});

(b). promise的 then方法返回一个promise。

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, 1000)
})
promise2 = promise1.then(res => {
    return new Promise((resolve,reject)=>{ 
        resolve('hello world'); 
    })
})
promise2.then(res => {
  console.log(res) //1秒后打印出:hello world
});
(4)实现一个Promise类
//创建一个Promise类
class Promise { 
    constructor(executor) {
        this.status = 'pending'; // 执行状态: 初始默认状态为pending(只有状态为pending才能转换状态)
        this.value = undefined;  // 执行结果:默认赋值为undefined
        this.reason = undefined; // 失败原因:默认赋值为undefined
        let resolve = (value) => {
            if (this.status === 'pending') { 
                this.value = value; //将传递进来的的值赋给value保存
                this.status = 'resolved'; //将状态设置成resolved
            }
        }
        let reject = (reason) => {
            if (this.status === 'pending') {
                this.reason = reason; //将传递进来的失败原因赋给reason保存
                this.status = 'rejected'; //将状态设置成rejected
            }
        }
        // 当代码出现错误的情况下,我们需要能够捕获错误,并且处理错误
        try{ 
            executor(resolve, reject); //默认执行executor
        }catch(e){
            reject(e);//如果发生错误,将错误放入reject中
        }
    }
    then(onFulfilled, onRejected) {  //等同于es5的Promise.prototype.then 当调用then的时候,根据状态,来执行不同的函数
        if (this.status === 'resolved') { 
            onFulfilled(this.value); //如果状态是resolved,执行成功的resolve,并将成功后的值传递过去
        }
        if (this.status === 'rejected') {
            onRejected(this.reason); //如果状态是rejected,执行失败的reject,并将失败原因传递过去
        }
    }
}

以上实现会有一个问题,如果promise内部使用setTimeout去调用回调函数时,我们会发现上面的代码在控制台完全没有反应,实际上是因为我们没有处理这种延迟调用的情况。

(5)setTimeout 调用问题
let promise = new Promise((resolve, reject) => {
    setTimeout(() =>{
        resolve('success');  //reject('fail')
  },1000);
});
promise.then((res)=>{
  console.log(res);
},(err)=>{
  console.log(err);
});

解决方法:【在上述代码基础上完善,如下代码】

class Promise { 
    constructor(executor) {
        ...此处略去部分代码
        this.successStore = [];  //定义一个存放成功函数的数组
        this.failStore = [];  //定义一个存放失败函数的数组
        let resolve = (value) => {
            if (this.status === 'pending') { 
                ...此处略去部分代码
                this.successStore.forEach(fn => fn()); //依次执行数组中的成功函数
            }
        }
        let reject = (reason) => {
            if (this.status === 'pending') { 
                ...此处略去部分代码
                this.failStore.forEach(fn => fn()) //依次执行数组中的失败函数
            }
        }
       ...此处略去部分代码
    }
    then(onFulfilled, onRejected) { //等同于es5的Promise.prototype.then 当调用then的时候,根据状态,来执行不同的函数
        ...此处略去部分代码
        if (this.status === 'pending') { //此处增加一种状态判断
            this.successStore.push(() => { //当状态为pending时将成功的函数存放到数组里
                onFulfilled(this.value);
            })
            this.failStore.push(() => { //当状态为pending时将失败的函数存放到数组中
                onRejected(this.reason);
            })
        }
    }
}

3.promise的then方法详解

Promise 对象的 then 方法接受两个参数:

promise.then(onFulfilled, onRejected);
(1)参数可选
(2)多次调用
(3)返回
promise2 = promise1.then(onFulfilled, onRejected);
promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);
(4)链式调用
a. 在then方法的回调里返回一个普通值。

无论是成功还是失败的回调,都会进入到下一个then()的成功态里。

let promise = new Promise((resolve, reject) => {
    resolve('success');
});
//返回一个普通值
promise.then(res => {  
    console.log(res); //success
  return "hello world";
}, err => {
    console.log(err); 
}).then(res => {
    console.log(res); //hello world
}, err => {
    console.log(err); 
})
b.在then方法的回调里返回一个新的Promise
let promise = new Promise((resolve, reject) => {
    resolve();
});
//返回一个新的Promise
promise.then((res)=>{  
    return new Promise((resolve,reject)=>{ 
        resolve('hello world'); 
    })
},(err)=>{
    console.log(err); 
}).then((res)=>{
    console.log(res); //hello world    
},(err)=>{
    console.log(err);
})

4.promise的其他方法的实现

(1)promise.catch 方法

相当于调用 then 方法, 但只传入 Rejected 状态的回调函数

catch (onRejected) {
    return this.then(undefined, onRejected);
}
(2)promise.reject 方法
static resolve (value) {
  return new Promise(resolve => reject(value));
}
(3)promise.resolve方法
static resolve (value) {
  return new Promise(resolve => resolve(value));
}
(4)promise.all 方法
static all(list){
    return new Promise((resolve, reject) => {
    let values = [];
    let count = 0;
   for (let [i, p] of list.entries()) {
      this.resolve(p).then(res => {
        values[i] = res;
        count++;
        // 所有状态都变成fulfilled时,就resolve
        if (count === list.length) {
            resolve(values);
        }
      }, err => {
        // 有一个被rejected时,就rejected
        reject(err);
      })
    }
  })
}

(5)promise.race 方法
static race (list) {
  return new MyPromise((resolve, reject) => {
    for (let p of list) {
     //有一个状态改变时,就rejected或resolve
      this.resolve(p).then(res => {
        resolve(res)
      }, err => {
        reject(err)
      })
    }
  })
}
(6)promise.finally 方法
finally (cb) {
  return this.then(
    value  => Promise.resolve(cb()).then(() => value),
    reason => Promise.resolve(cb()).then(() => { throw reason })
  );
};

5.promise其他方法的使用

(1)Promise.all( )
//成功
let p1 = new Promise((resolve,reject) => {
  let value = {
        code:0,
        msg:'one success'
    };
  resolve(value);
});
//成功
let p2 = new Promise((resolve,reject) => {
  let value = {
        code:1,
      msg:'two success'
  };
  resolve(value);
});
//失败
let p3 = new Promise((resolve,reject) => {
  let reason = 'all error';
  reject(reason);
});

Promise.all([p1,p2]).then((val) => {
  console.log(val);
}).catch(err=>{
  console.log(err);
});

输出结果:

输出结果
Promise.all([p1,p2,p3]).then(val => {
  console.log(val);
}).catch(err=>{
  console.log(err);
});

输出结果:

输出结果

【适合场景】

如上p1,p2,p3的三个情况,只有全部是成功的回调promise才会成功状态,若有一条失败则promise返回状态。

(2)Promise.race( )
//成功回调,直接返回
let p1 = new Promise((resolve,reject) => {
  let value = {
    code:0,
    msg:'one success'
  };
  resolve(value);
});

//成功状态,延迟1秒返回
let p2 = new Promise((resolve,reject) => {
  let value = {
    code:1,
    msg:'two success'
  };
 setTimeout(()=>{
     resolve(value);
  },1000);
});

//失败状态,延迟0秒返回   
let p3 = new Promise((resolve,reject) => {
  let reason = 'race error'
  setTimeout(()=>{
     reject(reason);
  },0);
});

Promise.race([p1,p2,p3]).then(val => {
  console.log(val);
}).catch(err=>{
  console.log(err);
})

输出结果:
为什么不输出延迟0秒的p3 ‘race error’ 呢,因为这个牵扯到事件执行机制,同步任务先执行,异步setTimeout任务挂起,同步任务执行结束之后再执行异步。所以p3没有p1返回的快。

输出结果

【适用场景】

如上p1,p2,p3,不管他们的状态是成功还是失败,只是返回最先执行完的那个。所以promise.race可以用于快捷地测试接口反应速度。


参考:https://juejin.im/post/5afd2ff26fb9a07aaa11786c

上一篇 下一篇

猜你喜欢

热点阅读