promise

70 阅读6分钟

promise

  • 作用: 一种新的异步代码封装方案,用来代替 回调函数的
    • promise 的三个状态
      • => 持续: pending
      • => 成功: fulilled
      • => 失败: rejected
  • promise 只会在持续状态转换为成功
    • 或者 从持续状态转换为 失败
  • promise 的基本语法:promise是JS内置的一个构造函数
    • const p = new Promise()
  • new Promise 得到的对象 我们叫做 promise 对象
  • promise 对象上 有一些方法
    • => then 方法 (会在promise状态成功的时候 执行)
    • => catch 方法 (会在promise状态失败的时候 执行)
    const p = new Promise(function(resolve, reject) {
      /**
       * 形参名无所谓
       *    第一个形参:内部的值是一个函数,调用之后可以将当前这个promise的状态设置为成功
       *    第二个形参:内部的值是一个函数,调用之后可以将当前这个promise的状态设置为失败
       * */ 
      const timer = Math.ceil(Math.random() * 3000)
      console.log('让A帮忙去买瓶水')
      setTimeout(() => {
        if(timer > 200) {
          console.log('买水成功,用时', timer)
          reject()
        } else {
          console.log('买水成功,用时', timer)
          resolve()
        }
      }, timer)
    }) 
    p.then(() => {
      console.log('如果我这行打印,说明promise的状态为 成功')
    })
    p.catch(() => {
      console.log('如果我这行打印,说明promise的状态为 失败')
    })

promise的链式调用1

    // 将promise封装到函数中
    function fn() {
      const p = new Promise(function(resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('让A帮忙去买瓶水')
        setTimeout(() => {
          if(timer > 1500) {
            console.log('买水成功,用时', timer)
            reject('买水失败是因为时间超过了1500毫秒')
          } else {
            console.log('买水成功,用时', timer)
            resolve('买水成功是因为时间小于1500毫秒')
          }
        }, timer)
      }) 
      return p
    }
    // 得到fn函数内部的promise对象
    const res = fn()
    // 普通调用
    // res.then(() => {
    //   console.log('如果我这行打印,说明promise的状态为 成功')
    // })
    // res.catch(() => {
    //   console.log('如果我这行打印,说明promise的状态为 失败')
    // })

    // 链式调用
    res.then((str) => {
      console.log('如果我这行打印,说明promise的状态为 成功', str)
    }).catch((str) => {
      console.log('如果我这行打印,说明promise的状态为 失败', str)
    })

promise的链式调用2

    // 将promise封装到函数中
    function fn() {
      const p = new Promise(function(resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('让A帮忙去买瓶水')
        setTimeout(() => {
          if(timer > 1500) {
            reject('超时,所以买水失败')
          } else {
            resolve('没有超时,买水成功')
          }
        }, timer)
      }) 
      return p
    }
    // 得到fn函数内部的promise对象
    const res = fn()
    // 普通调用
    // res.then(() => {
    //   console.log('如果我这行打印,说明promise的状态为 成功')
    // })
    // res.catch(() => {
    //   console.log('如果我这行打印,说明promise的状态为 失败')
    // })

    /**
     * 当你在第一个then里面返回一个新的promise对象
     * 然后你可以在第一个then的后面再次书写一个then
     * */ 
    // 链式调用
    res.then((str) => {
      console.log(`因为${str},所以奖励A10个bug`)
      return fn()
    }).then((str) => {
      console.log(`第二次买水成功`)
      return fn()
    }).then((str) => {
      console.log(`第三次买水成功`)
    }).catch((str) => {
      console.log(`买水失败`)
    })

async 与 await

  • 是promise 的一种调用方案 (也就是说必须结合着 promise 一起使用)
  • 能够将 异步代码,写得像"同步代码一样"
  • async: 书写在一个函数的开头,表明当前函数是一个异步代码,内部可以书写await
  • await: 具有等待含义,书写在异步函数前,代码运行到这个位置的时候,会有一个等待效果,一直等到这个异步任务结束,并且将异步任务的反馈结果 当一个值返回出来
    function fn() {
      const p = new Promise(function(resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('让A帮忙去买瓶水')
        setTimeout(() => {
          if(timer > 1500) {
            reject('超时,所以买水失败')
          } else {
            resolve('没有超时,买水成功')
          }
        }, timer)
      }) 
      return p
    }
    newFn()
    async function newFn() {
      // 因为函数开头写了async,所以这个函数就是一个独特的异步函数,内部可以书写await
      const r1 = await fn()
      console.log('第1次买水:', r1)
      const r2 = await fn()
      console.log('第2次买水:', r2)
      const r3 = await fn()
      console.log('第3次买水:', r3)
    }

async与await的缺点

  • 不能正常的捕获到promise 的失败状态
      1. try...catch
      1. 封装一个永远不会失败的promise
    • 也就是说 不管请求状态如何,永远调用resolve让promise的状态一定是成功
    • 为了区分这次请求是成功还是失败,我们不再单纯的返回一个字符串了,而是返回一个对象
  • 注意:这个对象 我们约定 里边有一个code属性,成功时赋值为1,失败时赋值为0
    function fn() {
      const p = new Promise(function(resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('让A帮忙去买瓶水')
        setTimeout(() => {
          if(timer > 1500) {
            // reject('超时,所以买水失败')
            resolve({
              code: 0, //代表当前请求失败
              msg: '超时,所以买水失败'
            })
          } else {
            // resolve('没有超时,买水成功')
            resolve({
              code: 0, //代表当前请求失败
              msg: '没有超时,所以买水成功'
            })
          }
        }, timer)
      }) 
      return p
    }
    newFn()
    // 解决缺点 方案2
    async function newFn() {
      const r1 = await fn()
      console.log(r1)
      if(r1.code === 0) {
        console.log('请求失败的补救措施')
      } else {
        console.log('请求成功,正常执行代码即可')
      }
    }
    // 解决缺点 方案1
    // async function newFn() {
    //   try {
    //     const r1 = await fn()
    //     console.log('第1次买水:', r1)
    //   } catch (error){
    //     console.log(error)
    //   }
    //   console.log('我是一个字符串,我的执行并不被打断')
    // }

promise的其他方法

    function fn() {
      const p = new Promise(function(resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('让A帮忙去买瓶水')
        setTimeout(() => {
          if(timer > 1500) {
            reject('超时,所以买水失败')
          } else {
            resolve('没有超时,买水成功')
          }
        }, timer)
      }) 
      return p
    }
    // 1. promise 对象上的方法
    // const res = fn()
    // res.then(() => {
    //   console.log('成功时执行')
    // }).catch(() => {
    //   console.log('失败时执行')
    // }).finally(() => {
    //   /**
    //    * 正常业务场景中,我们再发起一个请求,会将页面弹出一个遮罩层,然后在请求结束的时候 需要将这个遮罩层关闭
    //    * 这个时候如果放在then中 那么会有一个问题,就是请求失败的时候不会触发then
    //    * 所以我们一般不会放在then关闭遮罩层,而是放在finally中
    //    * */ 
    //   console.log('每一次都会执行(不会考虑成功还是失败)')
    // })

    // 2. Promise构造函数上的一些方法
    // Promise.all([fn(), fn(), fn()]).then(() => {
    //   console.log('所有的参数,全部都返回一个成功的状态的时候,会执行')
    // }).catch(() => {
    //   console.log('所有参数中,有一个为失败状态,就执行 catch')
    // })

    Promise.race([fn(), fn(), fn()]).then(() => {
      console.log('这些参数中,结束最快的那一个状态为成功的时候执行')
    }).catch(() => {
      console.log('这些参数中,结束最快的那一个状态为失败的时候执行')
    })
    3.promise的其他方法
    // Promise.allSettled([fn(), fn(), fn()]).then((res) => {
    //   /**
    //    * 在数组内传递的promise全都执行完毕后,返回一个数组给到then函数
    //    * 
    //    * 数组内的对象就是我们传递进来的promise对象的执行结果
    //    * */ 
    //   console.log(res)
    // })
    Promise.resolve().then(() => {
      console.log('强制返回一个状态为成功的promise')
    })
    Promise.reject().then(() => {
      console.log('如果我打印了,说明当前的promise状态为成功')
    }).catch(() => {
      console.log('强制返回一个状态为失败的promise对象')
    })