Promise对象

Promise

基本概念

  • 译为“承诺”,这也就表达了将来会执行的操作,代表异步操作;
  • 一共有三种状态,分别为 pending(进行中)、fulfilled(已成功)和 rejected(已失败)。
  • 特点
    1. 只有异步操作可以决定当前处于的状态,并且任何其他操作无法改变这个状态;
    2. 一旦状态改变,就不会在变。状态改变的过程只可能是:从 pending 变为 fulfilled 和从 pending 变为 rejected。如果状态发生上述变化后,此时状态就不会在改变了,这时就称为 resolved(已定型)
    3. 与事件( Event )的区别:事件错过了的话再去监听,是得不到结果的。
  • 缺点
    1. 无法取消 Promise,一旦新建它就会立即执行,无法中途取消;
    2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部;
    3. 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
  • Promise 的出现主要是解决地狱回调的问题,比如你需要结果需要请求很多个接口,这些接口的参数需要另外那个的接口返回的数据作为依赖,这样就需要我们一层嵌套一层,但是有了 Promise 我们就无需嵌套。
  • promise 的本质是什么:分离异步数据获取和业务

基本用法

Promise 对象是由关键字 new 及其构造函数来创建的。

1
2
3
4
5
6
7
8
const promise = new Promise((resolve, reject) => {
// do something here ...
if (success) {
resolve(value); // fulfilled
} else {
reject(error); // rejected
}
});
  • 该构造函数接收两个函数作为参数,分别是 resolve 和 reject。
  • 当异步操作执行成功后,会将异步操作结果作为参数传入 resolve 函数并执行,此时 Promise 对象状态从 pending 变为 fulfilled;
  • 失败则会将异步操作的错误作为参数传入 reject 函数并执行,此时 Promise 对象状态从 pending 变为 rejected;

通过 then 方法,分别指定 resolved 状态和 rejected 状态的回调函数。

1
2
3
4
5
6
7
8
promise.then(
function (value) {
// success
},
function (error) {
// failure
}
);
  • then 方法可以接收两个回调函数作为参数,第一个回调函数就是 fulfilled 状态时调用;
  • 第二个回调函数就是 rejected 时调用。这边的第二个参数是可选的,不一定要提供。

方法

Promise.resolve(value)

  • 返回一个以给定的值解析后的 Promise 对象;

  • 参数 value 主要有以下几种情况:

  • 一个 Promise 实例
    原封不动的返回该实例;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var original = Promise.resolve("我在第二行");
    var cast = Promise.resolve(original);
    cast.then(function (value) {
    console.log("value: " + value);
    });
    console.log("original === cast ? " + (original === cast));

    // "original === cast ? true"
    // "value: 我在第二行"
  • 一个 thenable 对象:是指含有 then 方法的对象
    跟随这个 thenable 对象的,采用它的最终状态;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let thenable = {
    then: function (resolve, reject) {
    resolve(42);
    },
    };

    let p = Promise.resolve(thenable);

    p.then(function (value) {
    console.log(value);
    });

    // 42
  • 普通数据:[String|Array|Object|Number]
    直接将传入参数当最终结果并返回一个新的 Promise;

    1
    2
    3
    4
    5
    6
    let p = Promsie.resolve(123);
    p.then(function (num) {
    console.log(num);
    });

    // 123
  • 无参数
    直接返回一个 resolved 状态的 Promise 对象

    1
    2
    3
    4
    let p = Promsie.resovle();
    p.then(function () {
    // do something here...
    });

Promise.reject(reason)

  • 参数:表示被拒绝的原因;
    传入的参数会原封不动的作为 reject 函数的理由,并不会因为传入的参数 Promise 或者是 thenable 对象而有所不同
  • 返回值:一个含有 reason 的状态为 rejected 的 Promise

promise.all()

  • Promise.all()方法将多个 Promise 实例包装成一个 Promise 对象(p),接受一个数组(p1,p2,p3)作为参数,数组中不一定需要都是 Promise 对象,但是一定具有 Iterator 接口,如果不是的话,就会调用 Promise.resolve 将其转化为 Promise 对象之后再进行处理。
  • 使用 Promise.all()生成的 Promise 对象(p)的状态是由数组中的 Promise 对象(p1,p2,p3)决定的。
    1. 如果所有的 Promise 对象(p1,p2,p3)都变成 fullfilled 状态的话,生成的 Promise 对象(p)也会变成 fullfilled 状态,p1,p2,p3 三个 Promise 对象产生的结果会组成一个数组返回给传递给 p 的回调函数。
    2. 如果 p1,p2,p3 中有一个 Promise 对象变为 rejected 状态的话,p 也会变成 rejected 状态,第一个被 rejected 的对象的返回值会传递给 p 的回调函数。
    3. Promise.all()方法生成的 Promise 对象也会有一个 catch 方法来捕获错误处理,但是如果数组中的 Promise 对象变成 rejected 状态时,并且这个对象还定义了 catch 的方法,那么 rejected 的对象会执行自己的 catch 方法。并且返回一个状态为 fullfilled 的 Promise 对象,Promise.all()生成的对象会接受这个 Promise 对象,不会返回 rejected 状态。

Promise 原型

Promise.prototype.then()

  • Promise 的实例具有 then 方法,主要作用是为 Promise 实例发生状态改变时添加回调函数。
  • 它接收两个回调函数作为参数,第一个参数是 fulfilled 状态时的回调函数;第二个参数是 rejected 状态时的回调函数,可不传入。
  • 并且该方法返回一个新的 Promise 对象。
1
2
3
4
5
6
7
8
9
10
p.then(onResolve, onReject);

p.then(
function (value) {
// fulfillment
},
function (reason) {
// rejection
}
);

Promise.prototype.catch()

返回一个 Promise,并且处理拒绝的情况。它的行为与调用 Promise.prototype.then(undefined, onRejected)相同。

1
2
3
4
5
p.catch(onReject);

p.catch(function (reason) {
// 拒绝
});

推荐使用 catch 方法,不要在 then 方法中定义 rejected 状态的回调函数;这是因为使用 catch 还可以捕获在 then 方法执行中存在的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// bad
p.then(
function (data) {
// success
},
function (err) {
// error
}
);

// good
p.then(function (data) {
// success
}).catch(function (err) {
// error
});

Promise.prototype.finally()

  • 返回一个 Promsie。是指,在上一轮 promise 运行结束后,无论 fulfilled 还是 rejected,都会执行指定的回调函数。

  • 该方法适合,无论结果如何都要进行的操作,例如清除数据。

  • 语法:该回调函数的不接受任何参数;

    1
    p.finally();

例子

axios 与 Promise 异步调用接口获取数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import axios from "axios";
import qs from "qs";
let instance = axios.create({
baseURL: "", // 基础url前缀
timeout: 10000,
});
function fetchApi(url) {
return new Promise((resolve, reject) => {
let param = {
//...
};
let config = {
headers: { "Content-Type": "multipart/form-data" },
};
instance
.post(url, qs.stringify(param), config)
.then(
(response) => {
resolve(response.data);
},
(err) => {
reject(err);
}
)
.catch((error) => {
reject(error);
});
});
}
function login() {
return fetchApi("/login");
}
login();