【JavaScript】14. 浅析Promise

283 阅读5分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

Promise

01. 是什么

  • Promise是:

    • 是异步编程的一种解决方法

    • 从语法上讲:Promise是一个对象,可以获取异步操作的消息

    • 从本意上讲:Promise表示承诺,它承诺过一段事件会给你一个结果

    • Promise创建后会立即执行


02. 为什么

  • Promise对象可以:
    • 表示一个异步操作最终完成(或者失败)及其结果值
    • 可以解决回调地狱的缺陷

03. 三种状态

  • 初始化状态:pending,表示操作进行中

  • 已兑现状态:fulfilled,表示操作成功

  • 已拒绝状态:rejected,表示操作失败

    Promise在创建时,状态为pending,状态一经改变就无法再改变

    且,状态改变只有两种情况:pending => fulfilledpending => rejected

    状态改变后,就称为resolved,表示状态已决定了


04. 结构

  • Promise是一个构造函数,需要结合new使用

    let promise = new Promise()
    
    
  • Promise接收一个函数作为参数,这个函数包含两个参数resolvereject

    • resolve :异步操作成功时调用,并会将成功结果作为参数传递出去
      • 其作用就是将Promise的状态从pending改变为resolved
    • reject:异步操作失败时调用,并将失败的错误作为参数传递出去
      • 其作用就是将Promise的状态从pending改变为rejected
    let promise = new Promise(function(resolve, reject){
        resolve(success)
        // reject(error)
    })
    
    
  • 即使异步操作已经完成(成功或失败),在这之后通过 .then() 添加的回调函数也会被调用

    • 通过多次调用 .then() 可以添加多个回调函数,它们会按照插入顺序进行执行

05. 返回值的处理

  • Promise中的任意返回值都会被包裹为promise对象,然后

    但不能返回Promise本身,否则死循环

  • .then()方法可以接受两个回调函数作为参数

    • 第一个回调函数是异步操作成功时调用
    • 第二个回调函数是异步操作失败时调用,非必填
    promise.then(
        function(success){
            // do something
        },
        function(error){
            // do something
        }
    )
    
  • .then()会在操作成功时执行,.catch()会在操作失败时执行

    • .catch()方法可以看作是.then(null,failureCallback)的缩略形式
    promise
        .then(()=>{
    		// success
    	})
        .catch(()=>{
    		// error
    	})
    
    
  • .finally方法在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数

    • 回调函数不需要传入参数
    • 其返回值也是一个Promise,是上一次的Promise对象的值
      • 如果是异常,则返回异常的Promise对象

Promise可以进行链式调用多次调用

  • 链式调用:Promise.then().catch()
  • 多次调用:Promise.then()Promise.then()
    • 但Promise的构造函数只会执行一次,且状态已经改变就不再变化

    • 因此,后续每次调用.then()或者.catch()都会直接拿到构造函数返回值


06. 关于返回错误:

  • .then()

    • 可以通过throw new Error()抛出错误
    • 可以通过return Promise.reject(new Error('错误信息'))返回错误
  • 接收错误

    • 通过throw抛出的错误,可以在.catch()中接收这个错误
    • 通过return返回错误,则会被包裹为Promise对象,无法被.catch()捕获
  • 在链式调用中,.catch()不管被链接到哪里,都可以捕获到上层未捕捉的错误


07. 值透传

  • .then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传

    Promise.resolve(1)
      .then(2)
      .then(Promise.resolve(3))
      .then(console.log)
    
    // 输出结果: 1
    

    第一个then和第二个then中传入的都不是函数

    • 一个是数字类型,一个是对象类型
    • 因此发生了透传,将resolve(1) 的值直接传到了最后一个then

08. 同步、异步

  • Promise新建后立即执行,即Promise构造函数里的代码同步执行

  • 而当Promise状态结束的时候,就会立即**放进异步队列中

    • .then()函数是异步的,需要在JS事件队列所有运行时间结束了,且事件队列被清空之后,才开始执行
    • .then()需要在回调函数resolve之后,才会执行里面的内容

09. async/await

  • 关于async / await

    async function foo() {
      // await 前面的代码
      await bar();
      // await 后面的代码
    }
    
    
  • 分析:

    • await 前面的代码 是同步执行的,

      • 它相当于函数foo内部的同步代码
      • 调用函数时会直接执行(当然要遵循事件循环机制)
    • await所在行的代码会从右往左执行,或者说,await后面的函数会先执行一遍

      • 它相当于Promise()构造函数内的代码
        • 注:是构造函数内,而不是回调函数
      • 所以它也是同步执行的
      • await表示等待右侧表达式完成
    • await 后面的代码则会被放到 Promise 的 .then() 方法里

    • 所以async/await可以转换为:

      function foo() {
          // await 前面的代码
          Promise(resolve => {
              bar()
              resolve()
          }).then(() => {
              // await 后面的代码
          });
      }
      
  • 错误处理

    • 如果await所在行的代码,后面返回的结果是一个状态为rejected的Promise对象
      • 那么,代码执行到这里就会返回结果,并且不会再继续向下执行
    • 为了避免这个问题
      • 可以在后面直接跟上.catch()
      • 可以使用try catch

10. .all().race()

  • Promise.all()接收一个Promise 对象数组作为参数

    • 它可以并行执行多个异步操作
    • 并且在所有异步操作执行完成后,才执行回调
    • 且只有全部为resolve时,才会在.then()里接收
    • 可以在.then()回调里接收所有的异步处理结果,结果顺序和数组顺序一致
  • Promise.race()接收一个Promise 对象数组作为参数

    • 它可以并行执行多个异步操作
    • 且,只会保留取第一个执行完成的异步操作的结果
    • 其它方法仍然会执行,不过执行结果会被抛弃

本人前端小菜鸡,如有不对请谅解