小白视角理解ES6中的promise

本文详细解析Promise在ES6中的概念,涉及状态改变方法、回调函数执行、then/catch顺序、then返回新promise状态决定因素、多任务串联、异常穿透及中断链机制。实例演示了如何在异步编程中利用Promise进行高效管理。
摘要由CSDN通过智能技术生成


内容参考:https://www.bilibili.com/video/BV1MJ41197Eu?p=19

Promise的概念

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。具体定义不再赘述,请参考阮一峰老师的 ECMAScript6 入门

问题1:如何改变promise的状态?

改变promise的状态有三种常用方式: 调用resolved()、调用reject(),和 throw 一个异常

    new Promise((resolve,reject)=>{
      // resolve(1) //会将promise状态变为resolved
      // reject(2) //会将promsie状态变为rejected
      throw 3 //会将promise 状态变为rejected
    }).then(
      value=>{
        console.log('resolved '+value)
      },
      reason=>{
        console.log('rejected '+reason)
      }
    )

问题2:一个promise指定多个成功/失败回调函数, 都会调用吗?

答案是肯定的。一个promise对象的状态在确定之后就不会再改变,并且可以在它的生命周期里一直被.then()\.catch()使用,当然也可以被多个.then()\.catch()使用

    const p = new Promise((resolve,reject)=>{
      resolve(1) //会将promise状态变为resolved
    })
    //第一组回调函数
    p.then(
      value=>{
        console.log('resolved A '+value)
      },
      reason=>{
        console.log('rejected A'+reason)
      }
    )
    //第二组回调函数
    p.then(
      value=>{
        console.log('resolved B '+value)
      },
      reason=>{
        console.log('rejected B'+reason)
      }
    )
    // resolved A 1
    // resolved B 1

问题3:改变promise状态 和 指定回调函数谁先谁后?

  • 都有可能
    从正常的逻辑上来说,我们应该在一个事情的结果还没有发生之前,就确定怎么去应对成功/失败的结果(林夕写的好:要拥有必先懂失去怎接受)。反映在这里,就是当promise的状态被确定为resolved还是rejected之前,我们就应该绑定好不同的回调函数来处理结果。在promise之前采用回调函数机制来实现异步操作,回调函数就要在执行异步操作之前就要绑定给异步操作。
    但是,promise恰恰打破了这种思路,无论promise是什么状态都可以绑定回调函数。例如:
  1. 在执行器中直接调用resolve()/reject()
const promise = Promise.resolve('哈哈直接成功')
   promise.then((value)=>{
   console.log(value)
})

说明一下,Promise.resolve(xxx)是一个API语法糖,用来快捷创建一个成功的promise对象,相当于new Promise((resolved,reject)=>{resolve(xxx)})
这里由于执行器函数是同步回调,所以在promise被new出来的时候就立马执行,将promise的状态确定为resolved。然后再通过.then()给它绑定回调函数。

  1. 延迟更长时间才调用then()
    const promise = new Promise((resolve,reject)=>{
      setTimeout(()=>{
        resolve(123)
      },1000)
    })
    promise.then(
      (value)=>{
        setTimeout(()=>{
          console.log(value)
        },1500)
      }
    )

延迟1s 调用resolve函数,但是1.5s后才调用回调函数。

【什么时候才能得到数据?】
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

问题4:promise.then()返回的新promise的结果状态由什么决定?

我们知道,.then() 对象会返回一个新的匿名promise对象,那么这个新对象的状态是如何确定的呢?

  • 简单来说,由then()指定的回调函数执行的结果决定。
  • 具体来说
    1. 如果抛出异常, 新promise变为rejected, reason为抛出的异常
    2. 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值(可以是undefined)
    3. 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
      举个例子:
    new Promise((resolve,reject)=>{
      resolve(1)
    }).then(
      (value)=>{
        console.log(value) //1  因为上一层promise是resolved
        return Promise.resolve(2)
      }).then(
        (value)=>{
          console.log(value) //2 因为上一层then返回的是Promise.resolve(2)
          return null
        }
      ).then(
        (value)=>{
          console.log(value)  //null 因为上一层then返回的是null,并没有异常,所以匿名promise对象也是resolved
          throw 3
        },
        (reason)=>{
          console.log("出错!")
          throw reason
          }
      ).then(
        (value)=>{
          console.log(value)
        },
        (reason)=>{
          console.log("出错!") // 出错,因为上一层then throw了一个异常,所以匿名promise对象就是rejected
          throw reason
          }
      )

问题5:promise如何串连多个操作任务?

(1)promise的then()返回一个新的promise, 可以开成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务

例子:

    new Promise((resolve,reject)=>{
      resolve(1)
    }).then(
      (value)=>{
        console.log("我是同步任务,value = "+value)
        return Promise.resolve(2)
      }).then(
        (value)=>{
          return new Promise((resolve,reject)=>{ //由于是异步任务,所以要封装在promise里,才能利用.then()让下面的函数等它
            setTimeout(()=>{
            console.log("我是异步任务,value = "+value)
            resolve(3) //别忘了resolve来确定匿名promise的状态,以出发下一个.then()里的回调函数
          },2000)
          })
        }
      ).then( //z这个then会等待上一个promise的结果确定才会被调用
        (value)=>{
          console.log("我是同步任务,value = "+ value)
          throw 404
        }
      ).catch(
        (reason)=>{
          console.log("出错啦!错误代码: "+reason)
        }
      )

问题6:如何理解promise异常穿透?

当使用promise的then链式调用时,可以在最后指定失败的回调,这样一来,前面任何操作出了异常, 都会传到最后失败的回调中处理。还是上面问题5那个案例:可以看到,每一层.then()我都只制定了onResolved函数,而没有写onRejected函数。实际上,当链上的一环发生错误后,它会去下一层.then()中寻找onRejected函数,如果没找到,那么会自动脑补一个onRejected函数:reason=>{throw reason},就像下面这样:

    .then(
        (value) => {
            console.log("我是同步任务,value = " + value)
            return Promise.resolve(2)
        }),
        (reason) => { throw reason}
    .then(
        (value) => {
            return new Promise((resolve, reject) => { //由于是异步任务,所以要封装在promise里,才能利用.then()让下面的函数等它
                setTimeout(() => {
                    console.log("我是异步任务,value = " + value)
                    resolve(3) //别忘了resolve来确定匿名promise的状态,以出发下一个.then()里的回调函数
                }, 2000)
            })
        },
        (reason) => { throw reason } // 脑补了这一行
    )

这样,异常就会顺着链条,直到最后的.catch()来处理它。

问题6:如何中断promise链?

如果在promise链中间就处理了异常,那么此时.catch()还是会返回一个新的promise对象,且无论它是resolved还是rejected,都会继续触发下面的.then()。此时怎么办?应该返回一个永远都是pending的promise对象,就相当于是中断了promise链。什么是永远都是pending的promise对象呢?一个空的promise对象。

    .catch(
        (reason) => {
            console.log("出错啦!错误代码: " + reason)
            return new Promise(() => { }) //返回一个永远都是pending的promise对象,就相当于是中断了promise链
        }
    )
    .then(
        (data) => {
            console.log("喂!上面的catch你不要再调用我啦~")
        }
    )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值