Declan's Blog

Hi, nice to meet you.

  1. 1. Promise 是什么
  2. 2. Promises/A+规范
    1. 2.1. onFulfilled 特性
    2. 2.2. onRejected 特性
    3. 2.3. 调用时机
    4. 2.4. 调用要求
    5. 2.5. 多次调用
    6. 2.6. 返回
  3. 3. 如何实现
    1. 3.1. 状态机
    2. 3.2. 状态变迁
    3. 3.3. 构造器
    4. 3.4. .done 方法
    5. 3.5. .then 方法

Promise 是什么

Promise 是异步编程的一种解决方案,比传统的回调函数和事件更加合理易用。它是一个容器,里面保存着某个未来才会结束的事件的结果,也是一个可以获取异步操作消息的对象。举个例子,如果想要使用 Promise API 异步调用一个远程的服务器,需要创建一个代表数据将会在未来由 Web 服务返回的 Promise 对象,目前数据还不可用,当请求完成并从服务器返回时数据将变为可用数据,在这个过程中,Promise 对象扮演一个数据的代理角色。在 Promise 对象上绑定一个回调函数,数据变得可用时这个回调函数将会被调用。

Promises/A+规范

Promise 是一个拥有 then 方法的对象或函数,并且其当前状态必须为一下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。

  • 等待态(Pending):可以迁移至执行态或拒绝态
  • 执行态(Fulfilled):不能迁移至其他任何状态,必须拥有一个不可变的终值
  • 拒绝态(Rejected):不能迁移至其他任何状态,必须拥有一个不可变的拒绝原因

一个 Promise 必须提供一个 then 方法以访问其当前值、终值和拒绝原因。

Promise 的 then 方法接收两个参数:

1
promise.then(onFilfilled, onRejected);

onFulfilled 和 onRejected 都是可选参数。

  • 如果 onFulfilled 不是函数,其必须被忽略
  • 如果 onRejected 不是函数,其必须被忽略

onFulfilled 特性

如果 onFulfilled 是函数:

  • 当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值
  • 在 promise 执行结束前其不可被调用
  • 其调用次数不可超过一次

onRejected 特性

如果 onRejected 是函数:

  • 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因
  • 在 promise 被拒绝执行前其不可被调用
  • 其调用次数不可超过一次

调用时机

onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用

调用要求

onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)

多次调用

then 方法可以被同一个 promise 调用多次

  • 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
  • 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调

返回

then 方法必须返回一个 promise 对象

1
promise2 = promise1.then(onFulfilled, onRejected);
  • 如果 onFulfilled 或者 onRejected 返回一个值 x,则运行下面的 Promise 解决过程:[Resolve]
  • 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  • 如果 onFulfilled 不是函数且 promise1 成功执行,promise2 必须成功执行并返回相同的值
  • 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的拒因

如何实现

状态机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
// 存储 state 状态,可以是 PENDING, FULFILLED or REJECTED
var state = PENDING;

// 存储 value 或者 error 当状态变为 FULFILLED 或者 REJECTED
var value = null;

// store sucess & failure handlers attached by calling .then or .done
// 存储通过.then 或.done 调用的成功和失败的处理器
var handlers = [];
}

状态变迁

仅支持两种状态变迁, fulfill 和 reject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...

function Promise() {
// ...

function fulfill(result) {
state = FULFILLED;
value = result;
}

function reject(error) {
state = REJECTED;
value = error;
}
}

fulfill 和 reject 方法较为底层,通常更高级的 resolve 方法开放给外部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...

function Promise() {
// ...

function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject);
return;
}
fulfill(result);
} catch (e) {
reject(e);
}
}
}

resolve 方法可以接受一个普通值或者另一个 promise 作为参数,如果接受一个 promise 作为参数,等待其完成。 promise 不允许被另一个 promise fulfill ,所以需要开放 resolve 方法。 resolve 方法依赖一些帮助方法定义如下:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 检查value是否为一个Promise,如果是的话返回那个promise的then方法
*
* @param {Promise|Any} value
* @return {Function|Null}
*/
function getThen(value) {
var t = typeof value;
if (value && (t === "object" || t === "function")) {
var then = value.then;
if (typeof then === "function") {
return then;
}
}
return null;
}

/**
* 设置resolver函数来保证onFulfilled和onRejected只被调用一次
*
* 不保证是异步
*
* @param {Function} fn
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false;
try {
fn(
function (value) {
if (done) return;
done = true;
onFulfilled(value);
},
function (reason) {
if (done) return;
done = true;
onRejected(reason);
}
);
} catch (ex) {
if (done) return;
done = true;
onRejected(ex);
}
}

这里 resolve 和 doResolve 之间的递归很巧妙,用来处理 promise 的层层嵌套( promise 的 value 是一个 promise )。

构造器

1
2
3
4
5
6
// ...

function Promise(fn) {
// ...
doResolve(fn, resolve, reject);
}

.done 方法

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
// ...
function Promise(fn) {
// ...

function handle(handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED && typeof handler.onFulfilled === "function") {
handler.onFulfilled(value);
}
if (state === REJECTED && typeof handler.onRejected === "function") {
handler.onRejected(value);
}
}
}

this.done = function (onFulfilled, onRejected) {
// 保证是异步调用
setTimeout(function () {
handle({
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
};
// ...
}

.then 方法

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
34
// ...
function Promise(fn) {
// ...
this.then = function (onFulfilled, onRejected) {
var self = this;
return new Promise(function (resolve, reject) {
return self.done(
function (result) {
if (typeof onFulfilled === "function") {
try {
return resolve(onFulfilled(result));
} catch (ex) {
return reject(ex);
}
} else {
return resolve(result);
}
},
function (error) {
if (typeof onRejected === "function") {
try {
return resolve(onRejected(error));
} catch (ex) {
return reject(ex);
}
} else {
return reject(error);
}
}
);
});
};
// ...
}

参考资料

  • Node.js 最新技术栈之 Promise 篇
  • Promises/A+
  • Promise 迷你书
This article was last updated on days ago, and the information described in the article may have changed.