promise async await

107 阅读6分钟

一、promise

作用:一种新的异步代码封装方式,用来代替回调函数的

promise 的三个状态

  • 1.持续:pending

  • 2.成功:fulfilled

  • 3.失败: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('班长,去帮我买瓶水')

      setTimeout(() => {
        if (timer > 1500) {
          console.log('买水失败,用时:超时', timer)
          // failure()
          reject()
        } else {
          console.log('买水成功,用时:', timer);
          // success()
          resolve()
        }
      }, timer)
    })
    // console.log('打印变量p', p);

    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('班长,去帮我买瓶水')

        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 的状态为失败'); })

    // 链式调用 (成功执行 then 失败执行 catch)
    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('班长,去帮我买瓶水')

        setTimeout(() => {
          if (timer > 1500) {
            // console.log('买水失败,用时:超时', timer)
            reject('超时,买水失败')
          } else {
            // console.log('买水成功,用时:', timer);
            resolve('没有超时,买水成功')
          }
        }, timer)
      })
      return p
    }

    // 得到 fn 函数内部的 promise 对象
    const res = fn()

    /**
     * 当你在第一个 then 里面返回一个新的 promise 对象
     * 然后你可以在第一个 then 的后面,再次书写一个 then 
    */

    // 链式调用 (成功执行 then 失败执行 catch)
    //链式调用的出现是为了解决调用地狱的问题
    res.then((str) => {
      console.log(`因为${str},所以奖励班长10个bug`)
      return fn()
    }).then((str) => {
      console.log('如果我输出了,表示班长第二次买水成功')
      return fn()
    }).then((str) => {
      console.log('如果我输出了,表示班长第三次买水成功')
    }).catch((str) => {
      console.log(`如果我输出了,说明之前某一次买水失败了`)
    })

    // .catch 必须放在最后

二、async 与 await

asyncawaitpromise 的一种调用方案(也就是说必须结合着 promise 一起使用

  • 作用:能够将异步代码写的像“同步代码”一样

  • async:书写在一个函数的开头,表明当前函数是一个异步函数,内部可以书写 await

  • await:具有等待的含义,书写在异步函数前,代码运行到这个位置的时候,会有一个等待效果

一直等到这个异步任务结束,并且将异步任务的反馈结果当一个值返回出来

    function fn() {
      const p = new Promise(function (resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('班长,去帮我买瓶水')

        setTimeout(() => {
          if (timer > 1500) {
            // console.log('买水失败,用时:超时', timer)
            reject('超时,买水失败')
          } else {
            // console.log('买水成功,用时:', timer);
            resolve('没有超时,买水成功')
          }
        }, timer)
      })
      return p
    }

    async function newFn() {
      // 因为函数开头写了 async 所以这个函数就是一个独特的异步函数,内部可以书写 await

      // await是等待的意思,他必须等待后边的 promise 结束后再往下继续执行代码
      const r1 = await fn()
      console.log('第一次买水:', r1);

      const r2 = await fn()
      console.log('第二次买水:', r2);

      const r3 = await fn()
      console.log('第三次买水:', r3);
    }
    newFn()

三、async 与 await 的缺点

不能正常的捕获到 promise 的失败状态

解决方法:

1. try ... catch
2.封装一个永远不会失败的 promise
  • 也就是说,不管请求状态如何,永远调用 resolvepromise 的状态一定是成功的

  • 为了区分这次请求是成功还是失败,我们不再单纯的返回一个字符串了

  • 而是返回一个对象

  • 注意:这个对象,我们约定里面有一个code 属性,成功赋值时为1, 失败时赋值为0

 function fn() {
      const p = new Promise(function (resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('班长,去帮我买瓶水')

        setTimeout(() => {
          if (timer > 1500) {
            // reject('超时,买水失败')
            resolve({
              code: 0, //0 代表当前请求失败
              msg: '超时,买水失败'
            })
          } else {
            // resolve('没有超时,买水成功')
            resolve({
              code: 1, //1 代表当前请求成功
              msg: '没有超时,买水成功'
            })
          }
        }, timer)
      })
      return p
    }

    // 方案2
    newFn()
    async function newFn() {
      const r1 = await fn()
      console.log(r1)
      if (r1.code === 0) {
        console.log('请求失败的补救措施')
      } else {
        console.log('请求成功,正常执行代码即可')
      }
    }

    // 解决缺点 方案1
    // newFn()
    // async function newFn() {
    //   try {
    //     const r1 = await fn()
    //     console.log('第一次买水:', 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('班长,去帮我买瓶水')

        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');
    // })

    // 3.
    Promise.race([fn(), fn(), fn()]).then(() => {
      console.log('这些参数中,结束最快的那一个状态为成功的时候执行');
    }).catch(() => {
      console.log('这些参数中,结束最快的那一个状态为失败的时候执行');
    })

promise 的其他方法2

    function fn() {
      const p = new Promise(function (resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('班长,去帮我买瓶水')

        setTimeout(() => {
          if (timer > 1500) {
            reject('超时,买水失败')
          } else {
            resolve('没有超时,买水成功')
          }
        }, timer)
      })
      return p
    }

    // 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 对象');
    })