Promise总结

134 阅读4分钟

简介

本质为class类,使用

new promise((resolve,reject)=>{

})

promise在实例化的时候就在执行

  • 缺点 首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

回调地狱

  • 多层嵌套的问题。
  • 每种任务的处理结果存在两种可能性(成功或失败),那么需要在每种任务执行结束后分别处理这两种可能性。 这两种问题在回调函数时代尤为突出。Promise 的诞生就是为了解决这两个问题。

Promise解决回调地狱

  • 回调函数延迟绑定
new Promise('1.json').then(data => {
  return readFilePromise('2.json')
});

回调函数不是直接声明的,而是在通过后面的 then 方法传入的,即延迟传入

  • 返回值穿透
let x = readFilePromise('1.json').then(data => {
  return readFilePromise('2.json')//这是返回的Promise
});
x.then(/* 内部逻辑省略 */)

根据 then 中回调函数的传入值创建不同类型的Promise, 然后把返回的 Promise 穿透到外层, 以供后续的调用。这里的 x 指的就是内部返回的 Promise,然后在 x 后面可以依次完成链式调用。

  • 错误冒泡
readFilePromise('1.json').then(data => {
    return readFilePromise('2.json');
}).then(data => {
    return readFilePromise('3.json');
}).then(data => {
    return readFilePromise('4.json');
}).catch(err => {
  // xxx
})

面产生的错误会一直向后传递,被 catch 接收到,就不用频繁地检查错误了

  • Promise进入微任务执行 异步操作结束后会调用 resolve 方法,或者中途遇到错误调用 reject 方法,这两者都是作为微任务进入到 EventLoop 中

回调的过程是异步的,解决浪费 CPU 性能的问题
放到当前宏任务最后执行,即加入微任务中,解决了回调执行的实时性问题

源码介绍

class Promise {
    constuctor(execute) {
        this.state = 'pengding'  //状态值
        this.value = ''  //成功值
        this.reason = '' //失败值
        this.onResolvedCallback = []  //存储成功的执行数组
        this.onRejectedCallbacks = [] //存储失败的执行数组
        function resolve(value) {
            //状态只能改一次,状态凝固
            if (this.state === 'pengding') {
                this.state = 'fulfilled'
                this.value = 'value'
                this.onResolvedCallback.forEach(fn => fn())
            }
        }

        function reject(value) {
            //状态只能改一次,状态凝固
            if (this.state === 'pengding') {
                this.state = 'rejected'
                this.value = 'value'
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }
        function resolvePromise(bridgePromise, x, resolve, reject) {
            //如果x是一个promise
            if (x instanceof MyPromise) {
                // 拆解这个 promise ,直到返回值不为 promise 为止
                if (x.status === PENDING) {
                    x.then(y => {
                        resolvePromise(bridgePromise, y, resolve, reject);
                    }, error => {
                        reject(error);
                    });
                } else {
                    x.then(resolve, reject);
                }
            } else {
                // 非 Promise普通值的话直接 resolve 即可
                resolve(x);
            }
        }

        //书写then方法
        then(onFullfied, onRejected){
            if (this.state === 'fulfilled') {
                return bridgePromise = new MyPromise((resolve, reject) => {
                    try {
                        // 状态变为成功,会有相应的 self.value
                        let x = onFulfilled(this.value);
                        // 暂时可以理解为 resolve(x),后面具体实现中有拆解的过程
                        resolvePromise(bridgePromise, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }
            if (this.state === 'rejected') {
                return bridgePromise = new MyPromise((resolve, reject) => {
                    try {
                        // 状态变为失败,会有相应的 self.error
                        let x = onRejected(this.reason);
                        resolvePromise(bridgePromise, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            }
            if (this.state === 'pending') {
                //将成功的时候需要干的事情
                this.onResolvedCallback.push(() => {
                    onFulfilled(this.value)  //使用闭包将每次的变量暂存下来,防止异步多次调用使用最后一次的数据
                })
                //将失败的时候要干的事,存起来
                this.onRejectedCallbacks.push(() => {
                    onRejected(this.reason)  //使用闭包将每次的变量暂存下来,防止异步多次调用使用最后一次的数据
                })
            }
        }
        //异常中断报错
        try {
            executor(resolve, reject)
        } catch (err) {
            reject(err)
        }
    }
}

// catch方法
Promise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected);
}

//Promise.resolve
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

//1.传参为一个 Promise, 则直接返回它
//2.传参为一个 thenable 对象,返回的 Promise 会跟随这个对象,`采用它的最终状态`作为`自己的状态`
//3.其他情况,直接返回以该值为成功状态的promise对象。
Promise.resolve = (param) => {
    if (param instanceof Promise) return param;
    return new Promise((resolve, reject) => {
        if (param && param.then && typeof param.then === 'function') {
            // param 状态变为成功会调用resolve,将新 Promise 的状态变为成功,反之亦然
            param.then(resolve, reject);
        } else {
            resolve(param);
        }
    })
}

//Promise.reject
var p = Promise.reject('出错了');
// 等价于
var p = new Promise((resolve, reject) => reject('出错了'))

Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason);
    });
}

//Promise.prototype.finally
Promise.prototype.finally = function(callback) {
    this.then(value => {
      return Promise.resolve(callback()).then(() => {
        return value;
      })
    }, error => {
      return Promise.resolve(callback()).then(() => {
        throw error;
      })
    })
  }


  //Promise.all 成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
  //传入参数为一个空的可迭代对象,则`直接进行resolve`
  //如果参数中`有一个`promise失败,那么Promise.all返回的promise对象失败
  //在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个`数组`
  Promise.all = function(promises) {
    return new Promise((resolve, reject) => {
      let result = [];
      let len = promises.length;
      if(len === 0) {
        resolve(result);
        return;
      }
      const handleData = (data, index) => {
        result[index] = data;
        // 最后一个 promise 执行完
        if(index == len - 1) resolve(result);
      }
      for(let i = 0; i < len; i++) {
        // 为什么不直接 promise[i].then, 因为promise[i]可能不是一个promise
        Promise.resolve(promise[i]).then(data => {
          handleData(data, i);
        }).catch(err => {
          reject(err);
        })
      }
    })
  }

  //Promise.race
  Promise.race = function(promises) {
    return new Promise((resolve, reject) => {
      let len = promises.length;
      if(len === 0) return;
      for(let i = 0; i < len; i++) {
        Promise.resolve(promise[i]).then(data => {
          resolve(data);
          return;
        }).catch(err => {
          reject(err);
          return;
        })
      }
    })
  }

promise.all接受是一个数组,里面可以是常量和promise,promise.all一个报错,其他还会执行

  • Promise.allSettled():接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是 fulfilled 还是 rejected,包装实例才会结束。返回值 allSettledPromise,状态只可能变成 fulfilled。它的监听函数接收到的参数是数组 results(含 fulfilled 的结果 or rejected 的结果)。
Promise.allSettled = Promise.allSettled || function(promises) {
        return new Promise(function(resolve, reject) {
            if (!Array.isArray(promises)) {
                return reject(
                    new TypeError("arguments must be an array")
                );
            }
            var resolvedCounter = 0;
            var promiseNum = promises.length;
            var resolvedValues = new Array(promiseNum);
            for (var i = 0; i < promiseNum; i++) {
                (function(i) {
                    Promise.resolve(promises[i]).then(
                        function(value) {
                            resolvedCounter++;
                            resolvedValues[i] = value;
                            if (resolvedCounter == promiseNum) {
                                return resolve(resolvedValues);
                            }
                        },
                        function(reason) {
                            resolvedCounter++;
                            resolvedValues[i] = reason;
                            if (resolvedCounter == promiseNum) {
                                return reject(reason);
                            }
                        }
                    );
                })(i);
            }
        });
    };
  • Promise.any():接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成 fulfilled状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态,参数为成员错误结果数组。

async / await

Promise 的语法糖,专门解决回调地狱,async 函数返回一个 Promise 对象。async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。

 async function f() {
     return 'hello world';
   }
   f().then(v => console.log(v))  //  "hello world"
   // 同时触发写法
   let [foo, bar] = await Promise.all([getFoo(), getBar()]);