Promise

一、Promise的理解和使用

Promise是JS中进行异步编程的新解决方案(旧方案是单纯使用回调函数)

从语法上来说,Promise是一个构造函数;从功能上来说,Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

Promise相对于回调函数的优势:

1. 支持链式调用,可以解决回调地狱问题

2. 指定回调函数的方式更加灵活

Promise可以包裹一个异步操作

    // 生成随机数
    function rand(m, n) {
      return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
    }
    // 点击按钮,1s后显示是否中将(30%概率中奖)
    const btn = document.querySelector('#btn')
    btn.addEventListener('click', function () {
      // Promise形式实现
      // resolve,reject两个参数都是函数类型的数据
      const p = new Promise((resolve, reject) => {
        setTimeout(() => {
          // 获取1-100的随机数
          let n = rand(1, 100);
          // 判断
          if (n <= 30) {
            resolve(n); //将promise对象p的状态设置为成功
          } else {
            reject(n); //将promise对象p的状态设置为失败
          }
        }, 1000);
      });
      // 调用then方法
      // 其中第一个回调是对象成功时的回调,第二个回调是对象失败时的回调
      p.then((value) => {
        alert('恭喜恭喜!中奖啦!,您的中将数字为' + value)
      }, (reason) => {
        alert('再接再厉,您的号码为' + reason)
      })
    })

Promise的状态

实例对象中的一个属性 [[PromiseState]]

pending 未决定的

resolved / fulfilled 成功

rejected 失败

Promise 对象的值

实例对象中的另一个属性 [[PromiseResult]]

保存着异步任务(成功/失败)的结果

只有resolve、reject这两个函数可以对这个值进行修改

 

 then用来指定成功和失败的回调,而catch只能指定失败的回调,catch等于是把then的后一个函数拆出来,单独做成语法糖

promise里面的函数是同步,它的then方法是异步

如果传入的参数为 非Promise 类型的对象,则返回的结果为成功的 promise对象

如果传入的参数为 Promise 类型的对象,则参数的结果决定了resolve的结果

 成功的结果是每一个promise对象成功的结果组成的数组,失败的结果是数组中失败的promise对象的结果

 “第一个完成”:同步任务先完成,异步任务后完成

二、promise的几个关键问题

1. 如何改变promise的状态?

(1)resolve函数,pending变resolved

(2)reject函数,pending变rejected

(3)抛出异常,pending变rejected

    let p = new Promise((resolve, reject) => {
      // 1.resolve函数
      // resolve('ok');  //pending => resolved(fulfilled)
      // 2.reject函数
      // reject('error');  //pending => rejected
      // 3.抛出错误
      throw '出问题了';
    });
    console.log(p);

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

(指定回调用then、catch方法)

当promise改变为对应状态时都会调用

    let p = new Promise((resolve, reject) => {
      resolve('ok');
    });
    // 指定回调-1
    p.then(value => {
      console.log(value);
    });
    // 指定回调-2
    p.then(value => {
      alert(value);
    });

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

指定回调函数 不是 执行回调函数

因为then是微任务,setTimeout是宏任务,所以同步任务执行完以后先去执行then,也就是指定了p改变状态时的回调函数,然后再执行定时器,执行了resolve('ok'),触发then里的回调

(1)都有可能,正常状态下是先指定回调再改变状态(执行器中是异步任务的情况居多),但也可以先改变状态再指定回调

(2)如何先改变状态再指定回调?

          a.在执行器中是个同步任务,直接调用resolve()/reject()

          b.延迟更长事件才调用then(),即定时器延迟时间更长

(3)什么时候才能得到数据?即回调什么时候执行

          a.如果先指定的回调,那当状态发生改变以后,回调函数才会调用,得到数据

          b.如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

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

(1)简单表述:由then()指定的回调函数执行的结果(返回值)决定

(2)详细表述:

          a.如果then的回调函数抛出异常,新promise变为rejected,reason为抛出的异常

          b.如果返回的是非promise的任意值,新promise变为resolved,value为返回的值

          c.如果返回的是另一个新promise,此promise的结果就会成为新promise的结果

    let p = new Promise((resolve, reject) => {
      resolve('ok');
    });
    let result = p.then(value => {
      // console.log(value);
      // 1.抛出错误
      // throw '出了问题';
      // 2.返回结果是非promise类型的对象
      // return 123;
      // 3.返回结果是Promise对象
      return new Promise((resolve, reject) => {
        reject('出错了')
      })
    }, reason => {
      console.warn(reason);
    });
    console.log(result);

5. promise如何串联多个操作任务?

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

    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('ok');
      }, 1000)
    });
    p.then(value => {
      return new Promise((resolve, reject) => {
        resolve('success');
      })
    }).then(value => {
      console.log(value);  //success
    }).then(value => {
      console.log(value);  //undefined
    })

6. promise异常穿透?

当使用promise的then链式调用时,可以在最后指定失败的回调。前面任何操作出了异常,都会传到最后失败的回调中处理

    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('ok');
        // reject('error');
      }, 1000)
    });
    p.then(value => {
      // console.log(111);
      throw '失败啦';
    }).then(value => {
      console.log(222);
    }).then(value => {
      console.log(333);
    }).catch(reason => {
      console.warn(reason); //失败啦
    })

7. 中断promise链?

当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数

办法:在回调函数中返回一个pending状态的promise对象

    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('ok');
      }, 1000)
    });
    p.then(value => {
      console.log(111);
      // 有且只有一种方式中断promise链条
      return new Promise(() => { }); //pending状态,没有改变状态,后面then无法执行
    }).then(value => {
      console.log(222);
    }).then(value => {
      console.log(333);
    }).catch(reason => {
      console.warn(reason);
    })

三、async 与 await

1. async 函数

函数的返回值为promise对象

async函数一定会返回一个promise对象。如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。

该promise对象的结果由async函数执行的返回值决定

和then的返回结果的规则一样

    async function main() {
      // 1.如果返回值是一个非Promise类型的数据
      // return 1351;
      // 2.如果返回的是一个Promise对象
      // return new Promise((resolve, reject) => {
      //   reject('ERROR');
      // });
      // 3.抛出异常
      throw 'Error'
    }
    let result = main();
    console.log(result);

2. await 表达式

await  操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。

await右侧的表达式一般为promise对象,但也可以是其他类型的值

如果表达式是promise对象,await返回的是promise成功的值

如果表达式式其他的值,直接将此值作为await的返回值

注意:

await必须写在async函数中,但async函数中可以没有await

如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值