Promise

ppgo8 于 2023-07-14 发布

Promise

Promise理论知识

promise本质 不是控制 异步代码的执行顺序(无法控制) , 而是控制异步代码结果处理的顺序

Promise是什么?

  1. 抽象表达

    • Promise是一门新的技术(ES6规范)

    • Promise是JS中进行异步编程的新解决方案(旧方案:使用回调函数)

      image-20230712213500402

      • 异步编程
        • fs 文件操作
        • 数据库操作
        • AJAX
        • 定时器
  2. 具体表达

    • 从语法上来说:Promise是一个构造函数
    • 从功能上来说:promise对象用来封装一个异步操作并可以获取其==成功/失败==的结果值

为什么用Promise?(优点)

Promise的状态

Promise对象的值

Promise的基本流程

image-20230712222027593

https://www.bilibili.com/video/BV1GA411x7z1/?p=13&spm_id_from=pageDriver&vd_source=dde2f4dd432156027fedf9b1734ba705

如何使用Promise

API

  1. Promise.prototype.then()

    • 定义

      then方法定义在原型对象Promise.prototype上,所以promise实例可以调用then方法。

    • 作用

      Promise实例添加状态改变时的回调函数

    • 返回值:返回一个新的promise实例对象

关键问题

  1. 如何改变promise对象的状态?

    const p = new Promise({
        // 1.改变为成功fulfilled/resovled
        resove('OK')
        // 2.改变为失败rejected
        reject('error')
        // 3.改变为失败
        throw '出问题了'
    })
    
  2. 一个promise对象指定多个回调函数,即多个then方法,都会执行吗?

    当promise对象状态改变为回调函数对应的状态时,==都会执行==。

    let p = new Promise((resove, reject) => {
            resove('OK')
        })
    // 当p的状态改变为成功时,下面两个回调都会执行
    // 若将resove('OK')注释掉,那么下面两个回调不会执行;因为promise对象状态没发生改变
    p.then(value => console.log(value))
    p.then(value => alert(value))
    

    如果是链式调用,那么会按照顺序执行then

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

    注意区分执行回调函数指定回调函数这两个概念。

    • 回调函数的执行肯定是在promise对象状态改变之后

    • 但是回调函数的指定与状态的改变顺序是不确定的。

    • 都有可能,正常情况下是先指定回调再改变状态,但也有可能先改变状态再指定回调。
    • 如何先改变状态再指定回调?
      • 执行器中直接调用resolve(),reject()
      • 延迟更长的时间才调用then()

    什么时候拿到数据,也就是回调函数什么时候执行?

    • 如果先指定回调,那么当状态发生改变时,回调函数就会调用,得到数据
    • 如果先改变状态,那么指定回调时,就会执行回调,得到数据
  4. peomise.then()返回的新promise的结果状态由什么决定?

    then方法会返回一个新的promise对象

    • 简单表达:由then中回调函数的结果决定
    • 详细表达:
      • 如果抛出异常,新promise变成rejected,reason为抛出异常
      • 如果返回的是非promise对象的任意值,新的promise变为resolved,value为返回值
      • 如果返回的是promise对象,此promise的结果会成为新的promise的结果,该promise的状态和结果决定了新promise的结果和状态
  5. promise如何串联多个操作任务?

    • promise的then()函数返回一个新的promise对象,因此可以开成.then()的链式调用
    • 通过then的链式调用串联多个同步/异步任务
  6. promise异常穿透?

    • 当使用promise的then链式调用时,可以在最后指定失败的回调,即catch

    • 前面的任何操作出了异常,都会传到最后的失败的回调中处理

      不考虑顺序

    const p = new Promise((resolve, reject) => {
        // resolve('ok')
        reject('error')
    })
    // 直接输出最后一个捕捉错误的catch
    p.then((value) => {
        console.log('@1', value);
        return value
    }).then((value) => {
        console.log('@2', value);
    }).catch((error) => {
        console.log(error);
    })
    
  7. 中断promise链

    • 需求:当使用promise的then链式调用时,在中间终端,不再调用后面的回调函数
    • 唯一方法:在回调函数中返回一个pendding状态的promise对象
      • 只有返回pendding状态的promise对象才可以终端promise
      • pendding状态的promise对象,它的then方法无法执行
    const p = new Promise((resolve, reject) => {
        resolve('ok')
        // reject('error')
    })
       
    p.then((value) => {
        console.log('@1', value);
        // 返回一个pendding状态的promise
        return new Promise(() => { }) // 后面的then不再执行
    }).then((value) => {
        console.log('@2', value);
    }).catch((error) => {
        console.log(error);
    })
    

自定义(手写)Promise

自己手写封装Promiese的全部功能。

async和await

Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担,并且Promise传递中间值⾮常麻烦。

async函数

await函数

注意

  • await必须写在async函数中,但async函数中可以没有await

  • 只有当await后面的异步操作执行完毕后,才会继续执行后面代码,因此保证了顺序

同时,在错误处理方面,用async/await会比的纯回调函数更方便,只需要使用try...catch包裹代码即可。

而且,在async/await方法中在,看不到回调函数形式的代码。

image-20230714092130018