Promise知识点总结(二)

180 阅读5分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

大家好,我是L同学,最近开始总结Promise的相关知识点。本文主要介绍了Promise对象方法:then方法catch方法finally方法

Promise对象方法 —— then方法

then方法是Promise对象上的方法。它其实放在Promise原型上的Promise.prototype.then。我们来看下Promise原型上有哪些方法.

console.log(Object.getOwnPropertyDescriptors(Promise.prototype));

image.png then方法接收两个参数,一个是fulfilled的回调函数,另一个是rejected的回调函数。

promise.then(res => {
  console.log(res);
}, err => {
  console.log(err);
})
// 等价于
promise.then(res => {
  console.log(res);
}).catch(err => {
  console.log(err);
})

then方法的参数是可选的,可以不传参数,那么promise状态会一层层传递,直到传递给有回调函数的then方法。

 const promise = new Promise((resolve, reject) => {
      resolve(100)
    })
    promise.then().then().then().then(res => {
      console.log(res);
    })
    
    // 相当于 将promise状态一层层传递
    // promise.then(value => value).then(value => value).then(value => value).then(res => {
    //   console.log(res);
    // })

image.png 同一个Promise的then方法可以被多次调用

当resolve回调函数被调用时,同一个Promise对象的所有then方法中的回调函数都会被调用。

const promise = new Promise((resolve, reject) => {
resolve('haha')
})

promise.then(res => {
console.log('res1', res);
})

promise.then(res => {
  console.log('res2', res);
})

promise.then(res => {
  console.log('res3', res);
})

then方法本身是有返回值的,返回一个Promise。如果我们在then方法中返回一个结果时,Promise会将这个结果作为resolve的参数

resolve不同值的区别

(1) 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数。

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

(2) 如果resolve传入另外一个Promise,那么这个新的Promise会决定原Promise的状态。

new Promise((resolve, reject) => {
  resolve(new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('新Promise的resolve')
    },3000)
  }))
}).then(res => {
  // 由resolve中新传入的Promise决定
  console.log(res);
})

等待3秒之后输出结果。

(3) 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行then方法,并且根据then方法的结果来决定Promise的状态。

new Promise((resolve, reject) => {
  resolve({
    then: function(resolve, reject) {
      resolve('thenable resolve')
    }
  })
}).then(res => {
  console.log(res); // thenable resolve
})

在then方法中,我们会返回不同的值。then方法会返回一个新的Promise对象,并将我们返回的值作为resolve回调函数的参数。然后我们需要根据上面所说的resolve不同值的区别来进行判定。

(1)then方法中,当我们返回的是一个普通值(数值/字符串/对象/undefined)时

promise.then(res => {
  /* 相当于
  return new Promise((resolve, reject) => {
    resolve('aaa')
  }) */
  return 'aaa'
}).then(res => {
  console.log(res); // aaa
})

(2)当我们返回的是一个Promise时

promise.then(res => {
/*   相当于
  return new Promise((resolve, reject) => {
    resolve(newPromise)
  }) */
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1111)
    }, 3000)
  })
}).then(res => {
  console.log(res);
})

(3)当我们返回的是一个对象,并且实现了thenable方法.

promise.then(res => {
/*   相当于
  return new Promise((resolve, reject) => {
    resolve({
      then...
    })
  }) */
  return {
    then: function(resolve, reject) {
      resolve(222)
    }
  }
}).then(res => {
  console.log(res); // 222
})

Promise对象方法 —— catch方法

catch方法也是Promise对象上的一个方法,它也是放在Promise的原型上的Promise.prototype.catch。和then方法一样,catch方法也可以被多次调用

const promise = new Promise((resolve, reject) => {
  reject('rejected status')
})

promise.catch(err => {
  console.log(err);
})

promise.catch(err => {
  console.log(err);
})

promise.catch(err => {
  console.log(err);
})

当executor抛出异常时,也会调用错误捕获的回调函数。

const promise = new Promise((resolve, reject) => {
  // reject('rejected status')
  throw new Error('rejected status')
})

promise.then(undefined, err => {
  console.log(err);
  console.log('------');
})

catch的返回值

catch方法也会返回一个Promise,在catch后面我们可以继续调用then方法或者catch方法。

下面的代码,后续是catch中的err2打印,还是then中的res打印呢?

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

promise.catch(err => {
  console.log('err1', err);
}).catch(err => {
  console.log('err2', err);
}).then(res => {
console.log('res', res);
})

image.png 答案是then方法中的res打印,res的结果是undefined。因为第一个catch方法返回了一个新的Promise,它的resolve值是默认返回的undefined,在执行完后默认状态依旧是fulfilled,所以执行then方法。

那么我们希望后续继续执行catch呢,那么需要抛出一个异常。

promise.catch(err => {
  console.log('err1', err);
  throw new Error('error message')
}).then(res => {
  console.log('res', res);
}).catch(err => {
  console.log('err2', err);
})

我们再看下面代码的运行结果。

const promise = new Promise((resolve, reject) => {
  reject('111')
})

promise.then(res => {
  console.log('res', res);
}).catch(err => {
  console.log('err', err);
  return 'catch return value'
}).then(res => {
  console.log('res result', res);
}).catch(err => {
  console.log('err result', err);
})

image.png

catch方法捕获不同地方的异常

(1) catch方法捕获原Poromise的异常。

const promiseA = new Promise((resolve, reject) => {
  reject('rejected status')
})
promiseA.then(res => {
  return 111
}).catch(err => {
  console.log('err',err); // err rejected status
})

(2) catch方法捕获新返回的Promise抛出的异常。

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

promise.then(res => {
  return new Promise((resolve, reject) => {
    reject(222)
  })
}).catch(err => {
  console.log('err',err); // err 222
})

常见错误

当写成以下代码时,会出现错误。这是因为then方法和catch方法是独立的,互不影响。当调用reject回调函数时,没有对错误进行捕获。

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

promise.then(res => {
  console.log(res);
})

promise.catch(err => {
  console.log(err);
})

Promise对象方法 —— finally

finally方法是ES9新增的特性。finally方法不接收参数,表示Promise对象无论变成fulfilled状态还是reject状态,最后都会被执行的代码。

const promise = new Promise((resolve, reject) => {
  // resolve('resolve message')
  reject('reject message')
})

promise.then(res => {
  console.log('res', res);
}).catch(err => {
  console.log('err', err);
}).finally(() => {
  console.log('finally');
})

finally方法后面可以链式调用then方法来拿到当前Promise对象最终返回的结果。

    function p1() {
      return new Promise((resolve, reject) => {
        resolve(100)
      })
    }
    p1().finally(() => {
      console.log('finally');
    }).then(res => console.log(res))

往期文章 👇👇👇

Promise知识点总结(一)

ES10和ES11常用知识点总结

ES7和ES8常用知识点总结

ES6常用知识点总结(三)

ES6常用知识点总结(二)

ES6常用知识点总结(一)

一个刚入职的前端程序媛的2021年终总结