JS关于promise

108 阅读5分钟

promise

  • 作用:一种新的一步的代码封装方案,用来代替回调函数的
  • prominse 的三个状态
    • 持续:pending
    • 成功:fulfilled
    • 失败:rejected
  • promise 只会在持续状态转换为 成功;或者 从持续状态转换为 失败
  • 基本语法:
    • promise 是JS内置的一个构造函数
    • const p = new Promise()
    • new Promise 得到的对象我们叫做 promise 对象
  • promise 对象上有一些方法
    • then 方法(会在 promise 状态成功的时候 执行)
    • catch 方法(会在 promise 状态失败的时候 执行)
    //将 promise 封装到函数中
    function fn() {
      const p = new Promise(function (resolve, reject) {
      /**
       * 形参名无所谓
       *    第一个形参: 内部的值是一个函数,调用之后可以将当前这个 promise 的状态设置为 成功
       *    第二个形参: 内部的值是一个函数,调用之后可以将当前这个 promise 的状态设置为 失败
      */

        //书写我们的 异步代码
        const timer = Math.ceil(Math.random() * 3000)
        console.log('班长,去帮我买瓶水')

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

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

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

    //链式调用(如果成功会执行.then如果失败了会跳过.then直接执行.catch)
    res.then((str) => {
      console.log(`因为${str},所以奖励班长10个bug`)

      return fn()
    }).then((str) => {
      console.log('如果我输出了,表示班长第二次买水成功')

      return fn()
    }).then((str) => {
      console.log('1如果我成功了,说明班长第三次买水成功')

    }).catch((str) => {
      console.log(`如果我输出了,说明${str},之前某一次买水失败了`)
    })

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

        setTimeout(() => {
          if (timer > 1000) {
            reject('买水失败,超时')
          } else {
            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
    function fn() {
      const p = new Promise(function (resolve, reject) {
        const timer = Math.ceil(Math.random() * 3000)
        console.log('班长,去帮我买瓶水')

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


async function newFn () {
    try {
        const r1 = await fn ()
        console.log('第一次买水',r1)
    } catch (error) {
        console.log(error)
    }
    console.log('我是一个字符串,我的执行并不会被打断')
}
  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('班长,去帮我买瓶水')

        setTimeout(() => {
          if (timer > 50) {
            resolve({
              code: 0, // 代表当前请求失败
              msg:'超时,所以买水失败'
            })
          } else {
            resolve({
              code:1, // 代表当前请求成功
              msg:'没有超时,买水成功'
            })
          }
        }, timer)
      })
      return p
    }
    newFn()
    
    
    async function newFn () {
        const r1 = await fn ()
        if(r1.code === 0){
            console.log('请求失败的补救措施')
        } else {
            console.log('请求成功')
        }
    }

promise 的其他方法

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

        setTimeout(() => {
          if (timer > 2000) {
            reject('买水失败,超时')
          } else {
            resolve('买水成功了')
          }
        }, timer)
      })
      return p
    }
  1. promise 对象上的方法
const res = fn ()
res.then(() => {
    console.log('成功时执行')
}).catch(() => {
    console.log('失败时执行')
}).finally(() => {
    console.log('每一次都会执行(不会考虑成功还是失败)')
})
    /**
       * 正常的业务场景中,我们再次发起一个请求的时候,会将页面弹出一个遮罩层,然后在请求结束的时候,需要将这个遮罩层关闭
       * 这个时候如果放在 then 中,那么会有一个问题,就是请求失败的时候不会触发 then
       * 所以我们一般不会放在 then 关闭遮罩层,而是放在 finally 中
      */
  1. promise 构造函数上的一些方法
Promise.all([fn(),fn(),fn()]).then(() => {
    console.log('所有的参数全部都返回一个成功状态的时候会执行')
}).catch(() => {
    console.log('所有的参数,有一个为失败状态的时候,会执行')
})
  1. promise 构造函数上的一些方法
    Promise.race([fn(),fn(),fn()]).then(() => {
      console.log('这些参数中,结束最快那一个状态为成功的时候执行');
    }).catch(() => {
      console.log('这些参数中,结束最快那一个状态为失败的时候执行');
    })
    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对象')
    })