(九) Promise异步编程

Promise

1. 为什么需要Promise

先看一个需求

通过ajax请求id, 再根据id请求用户名, 再根据用户名获取email

$.ajax({
      // 请求id
      type: 'GET',
      url: './data1.json',
      success: function (res) {
        const { id } = res

        // 根据id获取用户名
        $.ajax({
          type: 'GET',
          url: 'data2.json',
          data: { id },
          success: function (res) {
            const { username } = res

            // 根据username获取email
            $.ajax({
              type: 'GET',
              url: 'data3.json',
              success: function (res) {
                console.log(res);

                // 更多回调嵌套...
              }
            })
          }
        })
      }
    })

回调地狱

以上这种在回调函数中嵌套回调的情况, 我们称之为回调地狱

Promise解决了回调地狱

2. Promise的基本使用

Promise是一个构造函数, 通过new关键字实例化对象

语法

new Promise((resolve, reject) => {})
  • Promis接受一个函数作为参数
  • 在参数函数中接受两个参数 (也是函数)
    • resolve
    • reject

Promise实例

Promise实例有两个属性

  • state: 状态
  • result: 结果

1) promise状态

第一种状态: pending (准备 / 待解决 / 进行中)

第二种状态: fulfiled (已完成 / 成功)

第三种状态: rejected (已拒绝 / 失败)

2) promise状态的改变

通过调用resolve()reject()改变当前promise对象的状态

示例

const p = new Promise((resolve, reject) => {
  // resolve(): 调用函数, 使当前promise对象的状态改成 fulfilled
  resolve()
})
console.dir(p);

示例

const p = new Promise((resolve, reject) => {
  // reject(): 调用函数, 使 当前promise对象的状态改成 rejected
  reject()
})
console.dir(p);
  • resolve(): 调用函数, 使当前promise对象的状态改成 fulfilled
  • reject(): 调用函数, 使 当前promise对象的状态改成 rejected

promise状态的改变是一次性的

3) promise的结果

const p = new Promise((resolve, reject) => {
  // 通过给resolve() / reject() 传递参数, 改变  当前promise对象   的结果
  resolve('成功的结果')
  // reject('失败的结果')
})

console.dir(p);

image-20210713092356251

3. Promise的方法

查看Promise原型上的方法

image-20210713092834976

所有这些方法都可以应用于 Promise 对象的一个实例,并且所有这些方法依次返回一个新的Promise对象

1) then() 方法

作用: 拿到promise的结果并根据结果进行下一步操作

then()方法的参数:

  • 第一个参数是一个函数
  • 第二个参数也是一个函数

then方法的第一个参数是 resolved 状态的回调函数,第二个参数(可选)是 rejected 状态的回调函数

但是为了代码的可读性,我认为最好将它们分开 => 在catch中进行失败处理

then()方法的返回值: 是一个promise对象

示例

const p = new Promise((resolve, reject) => {
  resolve()
})

p.then(() => {
  // 当promise的状态时fulfilled时, 执行该函数
  console.log('成功时调用');
}, () => {
  // 当promise的状态时rejected时, 执行该函数
  console.log('失败时调用');
})

then()方法获取数据

示例

const p = new Promise((resolve, reject) => {
  // 通过给resolve() / reject() 传递参数, 改变  当前promise对象   的结果
  resolve('成功的结果')
  // reject('失败的结果')
})

p.then((res) => {
  // 当promise的状态时fulfilled时, 执行该函数
  // 这里的参数res是调用resolve时传递的参数   err同理
  console.log('成功时调用', res);
}, (err) => {
  // 当promise的状态时rejected时, 执行该函数
  console.log('失败时调用', err);
})

then()方法的返回值 => 是一个promise对象, 状态是 pending

因此可以采用链式写法,即then方法后面再调用另一个then方法。

示例

new Promise((resolve,reject) => {}).then().then().then()...

2) catch() 方法

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。

另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。

示例

    const p = new Promise((resolve, reject) => {      // 通过给resolve() / reject() 传递参数, 改变  当前promise对象   的结果      reject('失败的结果')    })    p.then((res) => {      // 当promise的状态时fulfilled时, 执行该函数      console.log('成功时调用', res);    })    p.catch((err) => {      // 当状态为rejected时, 执行该函数      console.log('失败了', err);    })		// 失败了 失败的结果

比较推荐的书写方法是先使用then来给promise添加resolve的回调,然后使用catch来捕获所有的链接上的reject或者异常。

3) 关于链式操作中promise状态的改变

首先要知道: promise的状态不改变, 不会执行then / catch里面的方法

// 如果promise的状态时pending,不会执行then/ catch中的方法new Promise((resolve, reject) => {}).then(() => {  console.log('成功');}).catch((err) => {  console.log('失败');})

在then中, 通过 return 可以将返回的新的promise实例改为fulfilled状态

new Promise((resolve, reject) => {  resolve('success data')})  .then((res) => {  return res})  .then((res) => {  console.log(res);})// success data

在then 中, 通过 抛出异常 可以将返回的新的promise实例改为rejected状态

new Promise((resolve, reject) => {  resolve('success data')})  .then((res) => {  console.log('成功');  // 这行代码会报错, 会将返回的promise对象的状态改成rejected  console.log(a);})  .then((res) => {  console.log('成功');}).catch((err) => {  console.log(err);})
posted @ 2021-08-02 22:42  只猫  阅读(111)  评论(0编辑  收藏  举报