es6 promise

  1. Promise 的含义
    Promise对象:
    三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
    状态一旦确定则无法改变。
    状态任意时候都可以得到,状态得到则Promise对象的回调函数,就会立即得到这个结果
    无法取消Promise,一旦新建它就会立即执行newpromise实例会立即执行)
    如果不设置回调函数,Promise内部抛出的错误,不会反应到外部

  2. 基本用法

    var promise = new Promise(function(resolve, reject) {
      resolve(sucessInfo)//当执行成功时可调用
      reject(failInfo)//当执行失败时可调用
      //resolve或reject一旦调用则状态凝固,其参数会被传递给回调函数
    })
    .then(function(sucessInfo) {
      // success
    }, function(failInfo) {
      // failure
    })
    

    reject函数的参数通常是Error对象的实例,表示抛出的错误;

    reject(new Error(this.failInfo));
    

    resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例

    const p1 = new Promise(function (resolve, reject) {
      // ...
    });
    
    const p2 = new Promise(function (resolve, reject) {
      // ...
      resolve(p1);
    })
    .then(function(sucessInfo){
    })
    

    这时p1的状态就会传递给p2,即p1的状态决定了p2的状态。
    如果p1的状态是pending(正在进行),那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

    let p1=new Promise((resolve,reject)=>{
        reject(2)
    })
    
    let p2=new Promise((resolve)=>{
        resolve(p1)
    })
    .then((val)=>{console.log(val)})
    .catch((val)=>{
        console.log(new Error(val))
    })
    /*Error: 2
    	at <anonymous>:10:18*/
    //可以发现即使外层的p2 resolve了,但是依然没有执行then,因为此时回调函数的状态取决于p1,p1 reject了,所以执行的回调函数是catch
    

    调用resolvereject并不会终结 Promise 的参数函数的执行(return才会)。
    resolvereject函数会把参数包裹成一个新的Promise

    立即 resolvedPromise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

    new Promise((resolve, reject) => {
      resolve(1);
      console.log(2);
    }).then(r => {
      setTimeout(()=>{
        console.log("aa")
      },1000)
      console.log(r);
    });
    console.log(3)
    // 2
    // 3
    // 1
    //aa
    
    1. 首先立即执行promise,发现resolve,把resolve放在微任务队列中,等到了本轮事件循环的末尾才能执行
    2. 执行打印,打印出2
    3. 状态未凝固,.then方法不执行,then方法被推入微任务队列中
    4. 执行打印,打印3
    5. 同步任务执行完了,所以把resolve从微任务队列推出到主线程执行
    6. promise状态凝固,微任务队列中的then方法回调函数达到执行条件,被推出微任务队列进入主线程执行队列执行
    7. 首先遇到settimeout函数,是一个宏任务(异步),被推入到宏任务执行队列,然后遇到同步任务,打印出resolve传递过来的1,这轮同步又执行完
    8. 如果1秒时间已经过去,则settimeout到达执行条件,被推入到主线程执行队列执行,打印出“aa"
    9. 总结:
      调用顺序是同步任务-》微观任务-》宏观任务
      promise是立即执行的
      resolve()是用来表示promise的状态为fullfilled,相当于只是定义了一个有状态的Promise,但是并没有调用它;
      promise调用then的前提是promise的状态已凝固;
  3. 规范写法
    一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。所以,最好在它们前面加上return语句,这样就不会有意外。

    new Promise((resolve, reject) => {
      return resolve(1);
      // 后面的语句不会执行
      console.log(2);
    })
    
  4. Promise.prototype.then()

    //前面第一段代码
    var promise = new Promise(function(resolve, reject) {
      resolve(sucessInfo)//当执行成功时可调用
      reject(failInfo)//当执行失败时可调用
      //resolve或reject一旦调用则状态凝固,其参数会被传递给回调函数
    })
    .then(function(sucessInfo) {//then方法的参数为两个回调函数,(可选),函数的参数sucessInfo为resolve函数的参数
      // success
    }, function(failInfo) {//参数failInfo为reject函数的参数
      // failure
    })
    .then(.....)//链式写法
    

    then方法返回的是一个新的Promise实例,因此可以采用链式写法,则第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

  5. Promise.prototype.catch()

    .catch相当于.then(null/undefined, rejection),用于指定发生错误时的回调函数,错误捕获会冒泡到外层,错误总是会被下一个catch语句捕获。.catch可以捕获前面的未被捕获的所有错误,catch()方法返回的还是一个 Promise 对象

       const p1 = new Promise((resolve, reject) => {
          setTimeout(() => resolve('成功'), 100)
        })
     
        const p2 = new Promise((resolve, reject) => {
          setTimeout(() => reject(new Error('失败了')), 100)
        })
     
        p1.then(function (post) {
          return p2
        })
        
        .then((resolve) => {
          //这里的代码不会执行,因为有错
          console.log('第二个then执行')
        })
        
        .catch((e) => {
          console.log(e, '=====第一个错误执行')
        })
        
        .catch((e) => console.log(e, '=====第二个错误执行'))
        //这里的代码不会执行,因为没有未捕获的错误
        
        .then((resolve) => {
          console.log('第三个then执行,接收到的返回值为:', resolve)
        })
        
        /*Error: 失败了
              at <anonymous>:6:35 "=====第一个错误执行"*/
        //第三个then执行,接收到的返回值为: undefined
    

    一般来说,使用catch方法捕获错误,不要在then()方法里面定义 Reject 状态的回调函数(即then的第二个参数)。
    Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

  6. Promise.prototype.finally()
    用于指定不管 Promise 对象最后状态如何,都会执行的操作,finally方法中的回调函数不接受任何参数
    finally方法总是会返回原来的值:

    // 不传参拿不到reject 的值
    Promise.reject(3).then(() => {}, () => {})
    //Promise {<fulfilled>: undefined}
    
    // 不传参也能拿到reject 的值
    Promise.reject(3).finally(() => {})
    //Promise {<rejected>: 3}
    
  7. Promise.all()
    用于将多个 Promise 实例,包装成一个新的 Promise 实例

    Promise.all([
      Promise.resolve(1),
      Promise.resolve(2),
    ])
    .then(([pro1, pro2]) => console.log(pro1, pro2));
    //1 2
    
    1. Promise.all()中所有参数状态都变成fulfilledPromise.all()才变成fulfilled,所有实例参数的返回值组成一个数组,传递给Promise.all()的回调函数
    2. Promise.all()中有一个参数被rejectedPromise.all()的回调函数会接收第一个被reject的实例的返回值
    3. 参数实例自己定义了catch方法,那么它一旦被rejected,会调用自己的catch方法,没有错误后状态变为fulfilled,并不会触发Promise.all()catch方法。
  8. Promise.race()
    将多个 Promise 实例,包装成一个新的 Promise 实例
    参数中有一个实例率先改变状态,Promise.race()的状态就跟着改变。该实例的返回值就传递给回调函数

    const p = Promise.race([
      promise1,
      new Promise(function (resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    ]);
    .then(console.log)
    .catch(console.error);
    

    以上为5 秒之内promise1无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数,反之在5秒内返回结果则触发then方法的回调函数。

  9. Promise.allSettled()
    参数数组的所有 Promise 对象都发生状态变更(不管是成功还是失败),Promise.allSettled()的状态则变为成功(不会是失败),调用then方法的回调函数,打印传过来的参数,是一个对象数组,为固定模式

    	//[{},{},...]
    	
    	// 异步操作成功时
    	{status: 'fulfilled', value: value}
    		
    	// 异步操作失败时
    	{status: 'rejected', reason: reason}
    
  10. Promise.any()
    Promise.all()相反:
    有一个变成fulfilled状态—>变成fulfilled状态
    所有参数实例都变成rejected状态—>变成rejected状态

  11. Promise.resolve()
    将现有对象转为 Promise 对象

    	Promise.resolve('foo')
    	// 等价于
    	new Promise(resolve => resolve('foo'))
    
参数类型情况详见 https://es6.ruanyifeng.com/#docs/promise#Promise-resolve
  1. Promise.reject()
    也会返回一个新的 Promise 实例,该实例的状态为rejected。
    其参数,会原封不动地作为reject的理由,变成后续方法的参数。

  2. Promise.try()
    database.users.get()返回一个 Promise 对象,如果抛出异步错误,可以用catch方法捕获;抛出同步错误(比如数据库连接错误,具体要看实现方法),这时你就不得不用try...catch去捕获

    try {
      database.users.get({id: userId})
      .then(...)
      .catch(...)
    } catch (e) {
      // ...
    }
    

    这时就可以统一用promise.catch()捕获所有同步和异步的错误;Promise.try就是模拟try代码块

    	Promise.try(() => database.users.get({id: userId}))
       .then(...)
       .catch(...)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值