手写promise

Promise 对象是用来处理异步操作的工具,解决开发者对异步回调的烦恼。

极简版

class Defer{
  succeed = null
  fail = null
  state = 'pending' 

  constructor(fn) {
    fn(this.resolve.bind(this), this.reject.bind(this))
  }
  
  resolve(result) {
    setTimeout(() => {
      this.state = 'fulfilled' 
      this.succeed(result)
    })
  }

  reject(reason) {
    setTimeout(() => {
      this.state = 'rejected' 
      this.fail(reason)
    })
  }

  then(succeed, fail) {
    this.succeed = succeed
    this.fail = fail
  }
}

  

1.Promise 参数 executor

当新建一个promise需要用户传递一个executor函数,其形参包含Promise自行传递的resolve,reject两个方法,分别表示代理的值解析成功并传递值,代理的值解析失败并传失败原因。而如果executor在执行过程中出错,则promise立即被拒绝(调用reject)。

function Defer(executor){ if(!(this instanceof Defer)){ throw 'Async is a constructor and should be called width "new" keyword'; } if(typeof executor !== 'function'){ throw 'Async params must be a function'; } try{ executor.call(this, this.resolve.bind(this), this.reject.bind(this));//传递resolve,reject方法 }catch(e){//报错立即拒绝 this.reject(e); } } Async.prototype = { constructor : Async, resolve : function(value){ this.value = value;//缓存代理的值 }, reject : function(reason){ this.rejectReason = reason;//缓存失败原因 } }

2.promise状态

Defer.prototype = { constructor : Async, resolve : function(value){ this.value = value;//缓存代理的值 this.status = 'resolved'; }, reject : function(reason){ this.rejectReason = reason;//缓存失败原因 this.status = 'rejected'; } }

3.then(onFulfilled,onRejected)重要部分

   then返回的是新的promise对象

//then中的onfulfilled传的参数为数值,则直接返回数值,如果为函数,则直接去调用函数。

   then参数调用时期和要求

(1) onFulfilled(onResolved):可选参数,如果不是函数则必须忽略;

(2) onRejected:可选参数,如果不是函数则必须忽略;

(3) 当promise成功执行,所有onFulfilled按注册顺序执行,如果promise被拒绝,所有onRejected按注册顺序执行;

(4) onFulfilled 和 onRejected必须作为纯函数调用

(5) promise的executor执行完毕并调用resolve或reject方可调用then参数onFulfilled 和 onRejected。

(6) 无论promise状态是resolved还是rejected,只要还有未执行onFulfilled,onRejected或catch(只处理reject状态)存在且调用,返回的promise均为resolved状态;(该规则在下一节”triggerThen处理”和下下节”catch异常“会有注释,一看便知)

对于规则4,必须作为传函数调用。所以传函数调用,是不包含在Object的属性当中直接引用,并且this的值是undefined。
  onFulfilled.call(undefined, promise_value);
对于规则5,等待executor执行完毕并调用resolve或reject方可调用then参数。then方法就是缓存参数。
function Defer(executor) {
            if (!(this instanceof Defer)) {
                throw 'Defer is a constructor and should be called width "new" keyword';
            }

            if (typeof executor !== 'function') {
                throw 'Defer params must be a function';
            }

            this.thenCache = [];//{resolve:,reject:}
            this.errorHandle = null;
            this.status = 'pendding';
            this.value = null;
            this.rejectReason = null;
            var self = this;
            setTimeout(function () {
                try {
                    executor.call(self, self.resolve.bind(self), self.reject.bind(self));//传递resolve,reject方法
                } catch (e) {
                    self.reject(e);
                }
            }, 0);
            return this;
        }

        Defer.prototype.resolve = function (value) {
            this.status = 'resolved';
            this.value = value;
            this.triggerThen();
        };
        Defer.prototype.reject = function (reason) {
            this.status = 'rejected';
            this.rejectReason = reason;
            this.triggerThen();
        };
        Defer.prototype.then = function (resolve, reject) {
            var todo = { resolve: resolve, reject: reject };
            this.thenCache.push(todo);
            return this;
        };
        Defer.prototype.triggerThen = function () {
            var current = this.thenCache.shift();
            var res = null;

            if (!current && this.status === 'resolved') {//成功解析并读取完then cache
                return this;
            } else if (!current && this.status === 'rejected') {//解析失败并读取完then cache,直接调用errorHandle
                if (this.errorHandle) {
                    this.value = this.errorHandle.call(undefined, this.rejectReason);
                    this.status = 'resolved';
                }
                return this;
            };

            if (this.status === 'resolved') {
                res = current.resolve;
            } else if (this.status === 'rejected') {
                res = current.reject;
            }

            if (typeof res === 'function') {
                try {
                    this.value = res.call(undefined, this.value || this.rejectReason);//重置promise的value
                    this.status = 'resolved';
                    this.triggerThen();//继续执行then链
                } catch (e) {
                    this.status = 'rejected';//异常,则promise为reject
                    this.rejectReason = e;
                    return this.triggerThen();//触发then链
                }
            } else {//不是函数则忽略
                this.triggerThen();
            }
        };
        Defer.prototype.catch = function (fn) {
            if (typeof fn === 'function') {
                this.errorHandle = fn;
            }
        }; 

手写promise.all

(方法返回一个promise实例,所有的promise都返回resolved,则resolved。如果有一个promise失败(rejected),则实例回调失败,失败原因返回第一个promise的结果)

Promise2.all = function(arrP) {
  let list = []
  let len = 0
  let hasErr = false
  return new Promise2((resolve, reject) => {
    for(let i = 0; i < arrP.length; i++) {
      arrP[i].then( data=> {
        list[i] = data
        len++
        len === arrP.length && resolve(list)
      }, error => {
        !hasErr && reject(error)
        hasErr = true
      })
    }
  })
}  

手写Promise.race

方法返回一个promise实例,一旦迭代器中的某个 promise 完成(resolved)或失败(rejected),返回的 promise 就会 resolve 或 reject   

返回第一个resolve或者reject的结果值。

Promise2.race = function(arrP) {
  let hasValue = false
  let hasError = false
  return new Promise2((resolve, reject) => {
    for(let i = 0; i < arrP.length; i++) {
      arrP[i].then(data => {
        !hasValue && !hasError && resolve(data) 
        hasValue = true
      }, error => {
        !hasValue && !hasError &&reject(error)
        hasError = true
      })
    }
  })
}

手写Promise.allSettled()

方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

适用于:多个彼此不依赖的异步任务完成时,可以知道每个promise的结果。

Defer.allSettled = function (values) {
            function isPromise(x) {
                if ((typeof x === 'object' && x != null) || typeof x === 'function') {
                    if (typeof x.then == 'function') {
                        return true;
                    }
                }
                return false;
            }
            return new Defer((resolve, reject) => {
                let arr = [];
                let times = 0;
                function collectResult(val, key, obj) {
                    arr[key] = obj;
                    if (++times === values.length) {
                        return resolve(arr);
                    }
                }
                // 循环每一项拿到返回结果
                values.forEach((element, index) => {
                    if (element && isPromise(element)) {
                        element.then(y => {
                            let obj = {
                                status: 'fulfilled',
                                value: y,
                            }
                            collectResult(y, index, obj)
                        }, (err) => {
                            let obj = {
                                status: "rejected",
                                reason: err
                            }
                            collectResult(err, index, obj)
                        })
                    } else {
                        let obj = {
                            status: 'fulfilled',
                            value: value,
                        }
                        collectResult(value, index, obj)
                    }
                });

            })
        }

手写promise.any()

返回第一个成功的 promise 。只要有一个 promise 成功此方法就会终止,它不会等待其他的 promise 全部完成。如果没有成功的,则将返回一个失败的promise和AggregateError类型的实例。是一个Error的子类,将用于把单一的错误集合在一起。

 Defer.any = function (values) {
            const num = values.length;
            const rejectedList = new Array(num);
            let rejectedNum = 0;
            return new Defer((resolve, reject) => {
                values.forEach((el, i) => {
                    Defer.resolve(el).then(
                        resolve(el)
                    ).catch(err => {
                        rejectedList[index] = err;
                        if (++rejectedNum === num) {
                            reject(rejectedList);
                        }
                    })
                })
            })
        } 

手写实现 Promise.prototype.finally()

finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。

实例执行完then或者catch触发,

Defer.prototype.finally=function(cb){
            return new Defer((resolve,reject)=>{
                this.then((result)=>{
                    cb();
                    resolve(result); 
                },(reason)=>{
                    cb();
                    reject(reason);
                })
            })
        }

代码完整:https://github.com/yaqian96/promise.git

 ----------------------------------------------------------------------------------------------补充版--------------------------------------------------------------------------------------------------------------------

1.如何中断promise

方法:返回一个pending的promise

2.异常穿透的现象是怎么回事

(1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
(2) 前面任何操作出了异常, 都会传到最后失败的回调中处理 

3.改变 promise 状态和指定回调函数谁先谁后?

(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2) 如何先改状态再指定回调?
  ① 在执行器中直接调用 resolve()/reject()
  ② 延迟更长时间才调用 then()
(3) 什么时候才能得到数据?
  ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
  ② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.promise的优点:①指定回调函数的方式更加灵活        ②解决地狱回调问题(防止一层层嵌套,套娃)

5.下图为promise的API

 

 

 

 

 

 

class Promise{
  constructor(executor){
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    this.PromiseState = PENDING;
    this.PromiseResult = null;
    this.callbacks = [];
    //保存实例对象的 this 的值
    const self = this;// self _this that
    //resolve 函数
    function resolve(data) {
      //判断状态
      if (self.PromiseState !== PENDING) return;
      //1. 修改对象的状态 (promiseState)
      self.PromiseState = FULFILLED;// resolved
      //2. 设置对象结果值 (promiseResult)
      self.PromiseResult = data;
      //调用成功的回调函数
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onResolved(data);
        });
      });
    }
    //reject 函数
    function reject(data) {
      //判断状态
      if (self.PromiseState !== PENDING) return;
      //1. 修改对象的状态 (promiseState)
      self.PromiseState = REJECTED;// 
      //2. 设置对象结果值 (promiseResult)
      self.PromiseResult = data;
      //执行失败的回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onRejected(data);
        });
      });
    }
    try {
      //同步调用『执行器函数』
      executor(resolve, reject);
    } catch (e) {
      //修改 promise 对象状态为『失败』
      reject(e);
    }
  }
  then(onResolved, onRejected) {
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason;
      }
    }
    if (typeof onResolved !== 'function') {
      onResolved = value => value;
      //value => { return value};
    }
    const _this = this;
    return new Promise((resolve, reject) => {
      // callback的封装
      function callback(type) {
        try {
          //执行成功回调函数
          let result = type(_this.PromiseResult);
          //判断
          if (result instanceof Promise) {
            result.then(v => {
              resolve(v);
            }, r => {
              reject(r);
            })
          } else {
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      }
      if (this.PromiseState === FULFILLED) {
        setTimeout(() => {
          callback(onResolved);
        });
      }
      if (this.PromiseState === REJECTED) {
        setTimeout(() => {
          callback(onRejected);
        });
      }
      //判断 pending 状态
      if (this.PromiseState === PENDING) {
        //保存回调函数
        this.callbacks.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          },
        })
      }
    })
  
  }
  catch(onRejected){
    return this.then(undefined, onRejected);
  }
  finally(value){
    return new Promise((resolve, reject) => {
      this.then((result) => {
        value();
        resolve(result);
      }, (reason) => {
        value();
        reject(reason);
      })
    })
  }
  static resolve(value) {
    //返回promise对象
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v);
        }, r => {
          reject(r);
        })
      } else {
        //状态设置为成功
        resolve(value);
      }
    });
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
  static all(promises) {
    // 在promise里边判断,长度与传入的长度比较,长度相等则执行resolve
    return new Promise((resolve, reject) => {
      let count = 0;
      let arr = []
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(data => {
          count++;
          arr[i] = data
          if (count === promises.length) {
            resolve(arr)
          }
        }, error => {
          reject(error)
        })
      }
    })
  }
  static any(promises) {
    // 只要其中的一个promise成功,则返回那个promise,如果失败则返回失败的集合
    return new Promise((resolved, rejected) => {
      let num = 0;
      let arr = []
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(data => {
          resolved(data)
        }, err => {
          num++;
          arr[i] = err;
          if (num === promises.length) {
            rejected(arr)
          }
        })
      }
    })
  }
  static race(promises) {
    // 谁先执行完就是谁
    return new Promise((resolved, rejected) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(data => {
          resolved(data)
        }, err => {
          rejected(err)
        })
      }
    })
  }
  static allSettled(values) {
    function isPromise(x) {
      if ((typeof x === 'object' && x != null) || typeof x === 'function') {
        if (typeof x.then == 'function') {
          return true;
        }
      }
      return false;
    }
    // 返回一个promise(都已经fulfilled或者rejected),并带有一个对象数组,每个对象都有对应的promise结果
    return new Promise((resolve, reject) => {
      let arr = []
      let times = 0;
      function collectResult(val, key, obj) {
        arr[key] = obj;
        if (++times === values.length) {
          return resolve(arr);
        }
      }
      // ①循环遍历数组
      for (let i = 0; i < values.length; i++) {
        if (values[i] && isPromise(values[i])) {
          values[i].then(y => {
            let obj = {
              status: 'fulfilled',
              value: y,
            }
            collectResult(y, i, obj)
          }, (err) => {
            let obj = {
              status: "rejected",
              reason: err
            }
            collectResult(err, i, obj)
          })
        } else {
          let obj = {
            status: 'fulfilled',
            value: value[i],
          }
          collectResult(value[i], i, obj)
        }
      }
    })
  
  }
  
}

async与await

async返回一个promise。await 后边可以是正常值,也可以是promise对象

posted @ 2020-12-28 16:37  yaqian96  阅读(130)  评论(0)    收藏  举报