Promise概述及应用

1.Promise概述

Promise是异步编程的解决方案。简单来说是一个容器,里面保存了异步操作的结果。Promise有如下特点:

  1. 对象内部状态不受外界环境影响。promise仅有三种状态pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前属于哪一种状态。
  2. 状态一旦确定就无法改变,任何时候都可以得到这个结果。promise的结果改变只有两种状态:从pending->fulfilled、从pending->rejected。只要这两个状态发生就无法改变。
    Promise的缺点:
  3. 无法取消Promise,一旦新建就会立即执行,无法中途取消。
  4. 如果不设置回调函数,promise内部抛出的错误无法被外界捕获。
  5. 当处于pending状态时,无法得知目前进展到哪一阶段。

注意:在构造Promise的时候,构造函数内部的代码是立即执行的。

2.基本用法

  • 通常使用new Promise构造一个新的promise函数。

    1
    2
    3
    4
    5
    6
    7
    8
    const promise = new Promise((resolve, reject) => {
    // ... some code
    if (/* 异步操作成功 */){
    resolve(value);
    } else {
    reject(error);
    }
    });
  • then()方法:接收两个回调函数,一个作为resolve状态回调,一个作为reject回调

    1
    2
    3
    4
    5
    promise.then(res=>{
    console.log(res) // value
    },err=>{
    console.log(err) // error
    })
  • catch()方法:接收一个回调函数,用来指定发生错误时的函数。相当于then方法的第二个函数。

    1
    2
    3
    4
    5
    6
    promise.then(res=>{
    console.log(res) // value
    })
    promise.catch(err=>{
    console.log(err) // error
    })
  • finally()方法:用于指定不管Promise对象最后状态如何,都会执行的方法。

    1
    2
    3
    4
    promise
    .then(res => {···})
    .catch(err => {···})
    .finally(() => {···})
  • all()方法:用于将多个Promise实例包装成一个新的Promise实例。只有多个Promise的返回状态都为resolve时新的Promise状态才为resolve,任意一个Promise状态为reject时新Promise状态为reject。如果参数Promise定义了自己的catch方法,那么一旦被rejected不会触发Promise.all()的catch方法。如果参数Promise没有自己的catch方法,则调用Promise.all()的catch方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const p = Promise.all([p1, p2, p3]);

    const p1 = new Promise((resolve, reject) => {
    resolve('hello');
    })
    .then(result => result)
    .catch(e => e);

    const p2 = new Promise((resolve, reject) => {
    throw new Error('报错了');
    })
    .then(result => result)
    .catch(e => e);

    Promise.all([p1, p2])
    .then(result => console.log(result))
    .catch(e => console.log(e));
    // ["hello", Error: 报错了]
  • race()方法:同样是将多个Promise实例包装成一个新Promise实例,与all不同的是:某一个参数Promise先改变状态,则返回率先改变的那个Promise的返回值,直接结束包装实例。

    1
    const p = Promise.race([p1, p2, p3]);
  • any()方法:只要有一个参数实例变成fulfilled状态,包装实例变成fulfilled状态,如果所有的实例都变成rejected状态,包装实例会变成rejected状态。与race方法类似,区别是:Promise.any()不会因为某个Promise变成rejected状态而结束,必须等到所有参数的Promise变成rejected状态才结束。

    1
    const p = Promise.any([p1, p2, p3]);
  • resolve()方法:将现有对象转化为Promise对象。

    1
    2
    3
    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))

    resolve参数分四种情况:

    1. 参数是一个Promise实例:Promise.resolve不做任何修改、原封不动返回这个实例。

    2. 参数是一个thenable对象(具有then方法的对象):Promise.resolve()方法会将这个对象转为Promise对象,然后立即执行thenable对象的then()方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      let thenable = {
      then: function(resolve, reject) {
      resolve(42);
      }
      };
      let p1 = Promise.resolve(thenable);
      p1.then(function (value) {
      console.log(value); // 42
      });
    3. 参数不是具有then()方法的对象,或根本就不是对象:如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。

      1
      2
      3
      4
      5
      const p = Promise.resolve('Hello');
      p.then(function (s) {
      console.log(s)
      });
      // Hello
    4. 不带有任何参数:Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      setTimeout(function () {
      console.log('three');
      }, 0);
      Promise.resolve().then(function () {
      console.log('two');
      });
      console.log('one');
      // one
      // two
      // three
  • reject()方法:返回一个新的 Promise 实例,该实例的状态为rejected。

1
2
3
4
5
6
7
8
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {
console.log(s)
});
// 出错了