Promise 的概念在 ES6 标准推出来之前已经深入人心,很多框架和第三方库都有类似的实现。但在深入理解 ES6 的 Promise 对象的时候,受之前经验的影响,很多概念给人似是而非的感觉,其中有一个特别明显的地方就是 ES6 中对 Promise 对象状态的定义以及 resolved 概念。
Promise 对象有三个状态:pending,fulfilled,rejected,MDN 文档上对 Promise 对象状态变化过程用一幅图描述:
图中有几个小细节:
,
- fulfilled
状态前 promise 都处在
- rejected
状态。
- pending
包括了
- settled
和
- fulfilled
。
- rejected
,
- pending
,
- fulfilled
三种状态下切换。
- rejected
事情在现在看来都很美好,状态清晰,一目了然。然而,在各种教程中我们会看到这样一个状态:
,阮老师的 ECMAScript 6 入门中直接把它当作了
- resolved
状态:
- fulfilled
Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
但是 MDN 中的备注是这样写的:
你可能也会听到一个术语
,它表示 Promise 对象处于
- resolved
状态,或者 Promise 对象被锁定在了调用链中。
- settled
嗯?记不记得上面提到
状态包括
- settled
和
- fulfilled
状态,那么他至少不能和
- rejected
状态划等号吧?于是我又搜了搜,发现网上很多文章提到
- fulfilled
这个词时,有人直接当作
- resolved
状态,有人把它理解为
- fulfilled
(类似地,
- complete
是 success,
- fulfilled
自然就是 error 或者 failure),不过更多人都是很含糊地引用了一下文档或者阮老师的文章。
- rejected
不过确实有人直接提出了这个问题:Promise 的 fulfill 和 resolve 为啥要用两个词?,我着重看了贺师俊老师的回答:
因为 fulfill 和 resolve 是不同的。 resolve 只是表示这个 promise 已经确定了,比如 promise A 被 resolve 为 promise B,则 A 已经 resolved 但是并未 fulfilled 。
好吧,我承认我一开始看没看懂... 不过还好在备注那里 MDN 放出了一篇帮助理解的文章,Domenic Denicola 的 States and Fates,基本把这两个概念说清楚了,不过文中只有简单的文字描述,下面说一下我自己的理解。
文章将 Promise 分得更细,分为了状态 (state) 和结果(fates,命运,原谅我粗浅的翻译)。
状态 (state) 就是上面提到的三种状态,需要稍微留意一下的是,文中提到
不是一种 Promise 状态,只是一种语义上的便利,说白了就是描述 Promise 确定了而已。
- settled
结果 (fates) 分为
和
- resolved
,两种结果互斥。
- unresolved
显而易见,只要理解了
的描述,自然就理解
- resolved
。首先先提一个 Promise 的概念,即当 Promise 的状态一旦改变,就永久保持该状态。所以什么时候没办法去 resolve 或 reject 一个 promise 对象呢?
- unresolved
和
- fulfilled
状态的 promise 对象,因为他们已经无法改变状态,而 resolve 和 reject 只能对
- rejected
状态的 promise 有效。
- pending
状态的 promise 对象也有可能处于
- pending
,当 promise 对象被'锁定'在另外一个 promise 对象或者一个非即时返回的
- resolved
函数中时,也就是上面贺老师提到的 promise A 被 resolve 为 promise B 这种情况,为了帮助理解,下面用代码举个例子。
- thenable
说明:Chrome(57.0.2987.133) 打印 promise 对象的时候,
有三个值:pending,resolved,rejected,这里的
- [[PromiseStatus]]
状态就是指
- resolved
状态,和我们要说明的
- fulfilled
没有关系,在 firefox(49.0.1) 中,
- resolved
三个值和标准相同:pending,fulfilled,rejected。为了避免混淆,用 firefox 做测试
- [[PromiseStatus]]
先上一个简单的代码:
- var p1 = new Promise((resolve, reject) => {
- setTimeout(resolve, 1000, 'p1 resolve');
- });
- p1.then(value => {
- console.log(value); // p1 resolve
- console.log(p1); // Promise { <state>: "fulfilled", <value>: "p1 resolve" }
- })
很简单,一秒后打印 p1 resolve,p1 对象状态为
。再来看第二例子,在 resolve 方法中新建了一个 Promise 对象:
- fulfilled
- var p1 = new Promise((resolve, reject) => {
- function F() {
- resolve(new Promise((resolve, reject) => {
- console.log(p1); // Promise { <state>: "pending" }
- setTimeout(resolve, 2000, 'new Promise resolve');
- }))
- }
- setTimeout(F, 1000, 'p1 resolve');
- });
- p1.then(function(value) {
- console.log(value); // new Promise resolve
- console.log(p1); // Promise { <state>: "fulfilled", <value>: "new Promise resolve" }
- })
运行一下发现,一秒后打印
- Promise { < state > :"pending"
- }
三秒后打印
- new Promise resolve Promise { < state > :"fulfilled",
- <value > :"new Promise resolve"
- }
可以看到,一秒后 p1 调用了 resolve 方法,和上一个例子一样被 resolve 了,理应变为
状态,但是他被'锁定'在了一个新的 Promise 对象中,所以状态没有立刻改变并执行
- fulfilled
方法,而是依然处于
- onfulfilled
状态,但是很明显的是,他的最终结果(这里可以体会到称为 fate 的原因,有种宿命的味道)就是
- pending
状态,此时的 p1 不能再 resolve 或 reject。再过了两秒后新 Promise 对象 resolve,p1 执行 then(),状态变为
- fulfilled
,打印的值也变成了 new Promise resolve,而不是 p1 resolve。此时打印出的 p1 的状态就是 fulfilled。
- fulfilled
到此,处于
状态的 promise 对象也有可能处于
- pending
情况就很清楚了,至于 unresolved,就是 promise 可以被 resolve 或 reject 的时候,此时 promise 对象一定处于
- resolved
状态且没有被 resolve 或 reject 为其他 Promise 对象 / 非即时返回的
- pending
函数。而反过来,处于
- thenable
状态的 promise 对象不一定是 unresolved。
- pending
到这里 Promise 对象的状态和 resolved 的概念差不多都清楚了,这篇文章也是我个人理解过程的一个记录。不过参考到的文章不多,文中的解释可能并不是很准确,所以在这里贴出来,希望能看看其他人的理解。
说起来,这篇文章离我上一篇文章已经很久了,真是光阴似箭,岁月...... 算了,还是不感慨了。现在工作确实没有在学校那会儿充足的时间和精力,总结还是有不少,大部分都在个人的笔记里,没有贴到博客。有些觉得总结份量不够,有些觉得个人的理解不深,不敢随意贴出来。不过在学习一些稍微深入一点的概念的时候,总觉得网上的一些资料并不是很全面和客观,人云亦云的东西太多,自己的理解也是七七八八。所以希望能够贴出来和大家交流,防止自己闭门造车,后续如果工作时间允许,会发一些这样的文章,对前端一些比较重要的知识点深入理解。
来源: http://www.cnblogs.com/JuFoFu/p/6692055.html