Promise 由基本使用到底层逻辑

在学习本章内容之前,需要先了解什么是异步编程 可以参看 JavaScript 异步编程 | 菜鸟教程

学习路线:

        1:应用:

          promise 是什么?

Promise是一个es6提供的类 , 目的是为啦更加优雅的书写复杂的异步任务。

因为Promise 是新增属性,所以都知道,一些旧版本不支持, 在官网可知:苹果的 Safari 10 和 Windows 的 Edge 14 版本以上浏览器才开始支持 ES6 特性。

  • 再此我先讲一些知识点:

        // bug: 只要是回调函数是就是异步的----> 错误的

        // good: 以前异步程序都是用回调函数编写

 

利用时间戳和setInterval 写一个简单的 setTimeout

 

 

 输出结果

 

          解决了什么问题?

1:回调地狱问题

2:代码的可读性问题

3:信任问题

 看一下回调地狱

在没有promise的时候 ,回调地狱太难受,痛点:可维护,可读性问题. 不是性能,不是内存问题

连环请求  :   痛点:太难看懂了. 所以就诞生了promise

 

          特点是什么?

 promise函数执行特点

 

          有哪些内容? 3个特殊属性

 promise实例有什么

  •  总结: promise程序执行特点: 有哪些内容
  • 回顾以前学过的promise
  • 总结 async await
  • 面试题:
    • 谈谈你对promise的理解? 说一下你在开发中如何使用promise的

    • 你是如何理解async await 函数的?

    • 为什么需要异步程序同步化

    • 扩展 es6有哪些新特点

          状态有几个? 3个

 

 

          原型api有哪些? 三个原型api : then()   catch()  finally()

原型api-then

        console.log(Promise);
        let p = new Promise((resolve,reject)=>{
            resolve(123)
            // reject()
        })
        console.log(p);
        p.test = '测试p p1'
        // console.log(Promise.prototype);
        //api: then catch finally
        
        // then
        // 作用:1:处理状态变为 已接受的请开给你
        //       2:获取p中[[PromiseResult]]的赋值
        //       3:实参二:处理 已拒绝状态的业务(不常用)
        // 返回值:全新的promise实例对象, 状态已接受,结果:undefined
        // 优势:支持then 链式调用
        // 弊端: then 停不下来
        let p1 =  p.then((res)=>{
            // 作用:  fulfilled(已接受) 状态情况下,处理的业务
            // 函数什么时候执行呢?
            // res 是什么呢?  p.[[PromiseResult]]的赋值
            console.log(res);
            // 问题:return 作用是什么? 是p.then() 的返回值
            return '给p1.[[PromiseResult]]赋值'

        },()=>{
            console.log('reject');
        })
        console.log(p1);
        // 如何获取p1.[[PromiseResult]]的值
        // p1.then(res=>{
        //     console.log(res);
        // })

        /*
        then 的作用是什么?
        then 的返回值是什么?
        then 中回调函数的作用是社么
        then 回调函数的形参作用是什么
        then 回到函数中的retrun的作用是什么
        */

 原型api-catch

 let p = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(123)
                // reject('errrr')
            },1000)
        })
        // then 的链式调用
        // let p1 = p.then(res=>{ // res=? 123
        //     return res+1
        // }).then(res=>{// res=? 124
        //     return 'ni'+res
        // }).then(res=>{ // res=? ni1234
        //     return 'hao'+res   // 去哪里了?         
        // })

        // // p1 接收的是什么?
        // // A haoni124
        // // B promise实例


        // 问:日志输出顺序是什么
        // A 1 2 3    因为都是微任务异步,按照顺序执行
        // B 1 2 3 4
        // let p1 = p.then(res=>{
        //     console.log(1);
        // }).then(res=>{
        //     console.log(2);
        // }).then(res=>{
        //     console.log(3);
        // }).catch(()=>{
        //     console.log(4);
        // })

        let p1 = p.then(res=>{
            console.log(1);
        }).then(res=>{
            console.log(2);
            // 1:在then的链式调用用,只要有一个出现问题,后面的都不执行,执行catch
            throw new Error('出错了出错了')
        }).then(res=>{
            console.log(3);
        }).catch((err)=>{
            // catch作用:1 捕获.then链式调用中的错误
            //           2 处理 promis对象 的 已经拒绝的状态
            console.log(4);
            console.log(err);
        })

        // catch()
        // 返回值是:pending状态的 全新的promise实例对象
        console.log(p1);
        /*
        catch 作用是什么
        catch 回调函数作用是什么
        catch 回调函数的形参赋值是什么
        catch 返回值什么
        catch 什么时候使用
            可以用户统一处理 promise的已拒绝的状态
        */

原型api-finally

        let p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(123)
            }, 1000)
        })
        let p1 = p.then(res=>{
            console.log(1);
        }).then(res=>{
            console.log(2);
        }).then(res=>{
            console.log(3);
        }).catch((err)=>{
            console.log(4);
            console.log(err);
        }).finally(()=>{
            // finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
            console.log('finally');
        })
        .then(res=>{
           console.log('验证finally后是否能够继续then');    
        })
        console.log(p1);

          静态api有哪些?4个:resolve()、reject()、all()和race()

1)Promise.resolve()

  •  此方法有一个可选的参数,参数的类型会影响它的返回值,具体可分为三种情况(如下所列),其中有两种情况会创建一个新的已处理的Promise实例,还有一种情况会返回这个参数。

        (1)当参数为空或非thenable时,返回一个新的状态为fulfilled的Promise。

        (2)当参数为thenable时,返回一个新的Promise,而它的状态由自身的then()方法控制,具体细节已在之前的thenable一节做过说明。

        (3)当参数为Promise时,将不做修改,直接返回这个Promise。

下面用一个例子演示这三种情况,注意观察Promise的then()方法的第一个回调函数中接收到的决议结果。

let tha = {
  then(resolve, reject) {
    resolve("thenable");
  }
};
//参数为空
Promise.resolve().then(function(value) {
  console.log(value);    //undefined
});
//参数为非thenable
Promise.resolve("string").then(function(value) {
  console.log(value);    //"string"
});
//参数为thenable
Promise.resolve(tha).then(function(value) {
  console.log(value);    //"thenable"
});
//参数为Promise
Promise.resolve(new Promise(function(resolve) {
  resolve("Promise");
})).then(function(value) {
  console.log(value);    //"Promise"
});

2)Promise.reject()

  此方法能接收一个参数,表示拒绝理由,它的返回值是一个新的已拒绝的Promise实例。与Promise.resolve()不同,Promise.reject()中所有类型的参数都会原封不动的传递给后续的已拒绝的回调函数,如下代码所示。

Promise.reject("rejected").catch(function (reason) {
  console.log(reason);          //"rejected"
});
var p = Promise.resolve();
Promise.reject(p).catch(function (reason) {
  reason === p;                 //true
});

第一次调用Promise.reject()的参数是一个字符串,第二次的参数是一个Promise,catch()方法中的回调函数接收到的正是这两个参数。

3)Promise.all()

 

 此方法和接下来要讲解的Promise.race()都可用来监控多个Promise,当它们的状态发生变化时,这两个方法会给出不同的处理方式。

Promise.all()能接收一个可迭代对象,其中可迭代对象中的成员必须是Promise,如果是字符串、thenable等非Promise的值,那么会自动调用Promise.resolve()转换成Promise。Promise.all()的返回值是一个新的Promise实例,当参数中的成员为空时,其状态为fulfilled;而当参数不为空时,其状态由可迭代对象中的成员决定,具体分为两种情况。

  (1)当可迭代对象中的所有成员都是已完成的Promise时,新的Promise的状态为fulfilled。而各个成员的决议结果会组成一个数组,传递给后续的已完成的回调函数,如下所示。

var p1 = Promise.resolve(200),
  p2 = "fulfilled";
Promise.all([p1, p2]).then(function (value) {
  console.log(value);          //[200, "fulfilled"]
});

(2)当可迭代对象中的成员有一个是已拒绝的Promise时,新的Promise的状态为rejected。并且只会处理到这个已拒绝的成员,接下来的成员都会被忽略,其决议结果会传递给后续的已拒绝的回调函数,如下所示。

var p1 = Promise.reject("error"),
  p2 = "fulfilled";
Promise.all([p1, p2]).catch(function (reason) {
  console.log(reason);         //"error"
});

4)Promise.race()

 此方法和Promise.all()有很多相似的地方,如下所列。

(1)能接收一个可迭代对象。

(2)成员必须是Promise,对于非Promise的值要用Promise.resolve()做转换。

(3)返回值是一个新的Promise实例。

新的Promise实例的状态也与方法的参数有关,当参数的成员为空时,其状态为pending;当参数不为空时,其状态是最先被处理的成员的状态,并且此成员的决议结果会传递给后续相应的回调函数,如下代码所示。

var p1 = new Promise(function(resolve) {
  setTimeout(() => {
    resolve("fulfilled");
  }, 200);
});
var p2 = new Promise(function(resolve, reject) {
  setTimeout(() => {
    reject("rejected");
  }, 100);
});
Promise.race([p1, p2]).catch(function (reason) {
  console.log(reason);      //"rejected"
});

   

  • 在p1和p2的执行器中都有一个定时器。由于后者的定时器会先执行,因此通过调用Promise.race([p1, p2])得到的Promise实例,其状态和p2的相同,而p2的决议结果会作为拒绝理由被catch()方法中的回调函数接收。
  • 根据前面的分析可以得出,Promise.all()能处理一个或多个受监控的Promise,而Promise.race()只能处理其中的一个。

总结promise实例

    <!-- 
        总结
        1: promise 实例对象创建有几种方式
          1.1 new Promise
          1.2 then的返回值
          1.3 catch 的返回值
          1.4 finally 的返回值
          1.5 async 函数的返回值
        2: 更改promise状态有什么方式
           resove()  fulfilled 已接受
           reject()  rejected  已拒绝

        3: [[PromiseResult]] 赋值有几种方式
           2.1 resolve reject的实参
           2.2 then 的return
           2.3 async 的return 
           注意:[[PromiseResult]] 赋值永远不可能是promise实例对象
               当[[PromiseResult]] 赋值为 prosmie实例时候。它会赋值该promise实例的.[[PromiseResult]]
               
        4: [[PromiseResult]] 取值有哪些方式
           4.1 then的回参
           4.2 await 返回值

     -->
     <script>
        // 常见写法
        // 1: 自己怎么利用promise进行封装
        // 2: 别人写好的怎么用
        // function foo() {
        //     // 创建了promise 对象. 
        //     // 在堆内存中共开辟了一个空间,产生了一个地址
        //     // return promise对象在堆内存中的地aaabb
        //     return new Promise((resolve,reject)=>{
        //         // .... 写一堆待完成代码
        //         setTimeout(() => {
        //             resolve('输出运算结果')
        //         }, 1000);
        //     })
        // }
        // // 分析程序:
        // // 1:执行哪个函数?
        // // 2:返回值是什么?
        // // 3:[[PromiseResult]] 赋值什么?

        // function bar(){
        //     let f = foo();
        //     f.text = '测试 bar 返回值与foo返回值是否为同一个promise'
        //     console.log(f);
        //     return f
        //     //  foo return
        //     //  aabb地址

        // }

        // function fun(){
        //     let b = bar()
        //     console.log(b);
        //     return b
        //     // bar return
        //     // aabb地址
        // }
        // function test(){
        //     // fun的return aabb地址
        //     // aabb 指向 foo执行创建的promise对象
        //     fun().then(res=>{
        //         console.log(res);
        //     })
        // }

        // test()

        // 已知 foo bar fun 返回值都是promise实例对象,
        // 问题:foo bar fun 返回值是一个promise实例对象 还是 3个promise实例对象
        // -----> 一个promise实例,
        // 问题 promise.[[PromiseResult]]的赋值是什么
        // ----> resolve() 实参 ---> ‘输出运算结果'’

        // let p = new Promise()
        // let a = p;
        // let b = a;
        // let c = b;
        

        // ----------------- 深入:promise async综合------------------


        function foo() {
    
            return new Promise((resolve,reject)=>{
                setTimeout(() => {
                    resolve('输出运算结果')
                }, 1000);
            })
        }

       async function bar(){
            let f = foo();
            f.text = '测试 bar 返回值与foo返回值是否为同一个promise'
            console.log(f);
            return f

    
        }

        function fun(){
            // 结论:bar foo 返回值不是一个promise实例对昂
            // bar 返回的promise.[[PromiseResult]] = foo返回的promise.[[PromiseResult]]
            let b = bar()
            // 运算过程:
            //  async 输出全新promise实例
            //  [[PromiseResult]] = async retrun
            //  [[PromiseResult]] = foo输出的promise实例
            // -----> [[PromiseResult]] 禁止赋值promise实例
            //  [[PromiseResult]] = foo输出的promise实例.[[PromiseResult]]
            // [[PromiseResult]] = '输出运算结果'
        
            console.log(b);
            return b
        }
        function test(){
            fun().then(res=>{
                console.log(res);
            })
        }

        test()

      在什么时候使用?

        2:promise A+

           制定promise的规范。

        3:基于原型或者class类如何手写promise。promise的原理是什么?

手写 Promise

       // 判断变量否为function
  const isFunction = variable => typeof variable === 'function'
  // 定义Promise的三种状态常量
  const PENDING = 'PENDING'
  const FULFILLED = 'FULFILLED'
  const REJECTED = 'REJECTED'

  class MyPromise {
    constructor (handle) {
      if (!isFunction(handle)) {
        throw new Error('MyPromise must accept a function as a parameter')
      }
      // 添加状态
      this._status = PENDING
      // 添加状态
      this._value = undefined
      // 添加成功回调函数队列
      this._fulfilledQueues = []
      // 添加失败回调函数队列
      this._rejectedQueues = []
      // 执行handle
      try {
        handle(this._resolve.bind(this), this._reject.bind(this)) 
      } catch (err) {
        this._reject(err)
      }
    }
    // 添加resovle时执行的函数
    _resolve (val) {
      const run = () => {
        if (this._status !== PENDING) return
        this._status = FULFILLED
        // 依次执行成功队列中的函数,并清空队列
        const runFulfilled = (value) => {
          let cb;
          while (cb = this._fulfilledQueues.shift()) {
            cb(value)
          }
        }
        // 依次执行失败队列中的函数,并清空队列
        const runRejected = (error) => {
          let cb;
          while (cb = this._rejectedQueues.shift()) {
            cb(error)
          }
        }
        /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
          当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
        */
        if (val instanceof MyPromise) {
          val.then(value => {
            this._value = value
            runFulfilled(value)
          }, err => {
            this._value = err
            runRejected(err)
          })
        } else {
          this._value = val
          runFulfilled(val)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加reject时执行的函数
    _reject (err) { 
      if (this._status !== PENDING) return
      // 依次执行失败队列中的函数,并清空队列
      const run = () => {
        this._status = REJECTED
        this._value = err
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(err)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加then方法
    then (onFulfilled, onRejected) {
      const { _value, _status } = this
      // 返回一个新的Promise对象
      return new MyPromise((onFulfilledNext, onRejectedNext) => {
        // 封装一个成功时执行的函数
        let fulfilled = value => {
          try {
            if (!isFunction(onFulfilled)) {
              onFulfilledNext(value)
            } else {
              let res =  onFulfilled(value);
              if (res instanceof MyPromise) {
                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                res.then(onFulfilledNext, onRejectedNext)
              } else {
                //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                onFulfilledNext(res)
              }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        // 封装一个失败时执行的函数
        let rejected = error => {
          try {
            if (!isFunction(onRejected)) {
              onRejectedNext(error)
            } else {
                let res = onRejected(error);
                if (res instanceof MyPromise) {
                  // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                  onFulfilledNext(res)
                }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        switch (_status) {
          // 当状态为pending时,将then方法回调函数加入执行队列等待执行
          case PENDING:
            this._fulfilledQueues.push(fulfilled)
            this._rejectedQueues.push(rejected)
            break
          // 当状态已经改变时,立即执行对应的回调函数
          case FULFILLED:
            fulfilled(_value)
            break
          case REJECTED:
            rejected(_value)
            break
        }
      })
    }
    // 添加catch方法
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }
    // 添加静态resolve方法
    static resolve (value) {
      // 如果参数是MyPromise实例,直接返回这个实例
      if (value instanceof MyPromise) return value
      return new MyPromise(resolve => resolve(value))
    }
    // 添加静态reject方法
    static reject (value) {
      return new MyPromise((resolve ,reject) => reject(value))
    }
    // 添加静态all方法
    static all (list) {
      return new MyPromise((resolve, reject) => {
        /**
         * 返回值的集合
         */
        let values = []
        let count = 0
        for (let [i, p] of list.entries()) {
          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
          this.resolve(p).then(res => {
            values[i] = res
            count++
            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
            if (count === list.length) resolve(values)
          }, err => {
            // 有一个被rejected时返回的MyPromise状态就变成rejected
            reject(err)
          })
        }
      })
    }
    // 添加静态race方法
    static race (list) {
      return new MyPromise((resolve, reject) => {
        for (let p of list) {
          // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
          this.resolve(p).then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        }
      })
    }
    finally (cb) {
      return this.then(
        value  => MyPromise.resolve(cb()).then(() => value),
        reason => MyPromise.resolve(cb()).then(() => { throw reason })
      );
    }
  }

  console.log(MyPromise);

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值