ES6 Promise 状态解惑
Promise的概念在ES6标准推出来之前已经深入人心,很多框架和第三方库都有类似的实现。但在深入理解ES6的Promise对象的时候,受之前经验的影响,很多概念给人似是而非的感觉,其中有一个特别明显的地方就是ES6中对Promise对象状态的定义以及resolved概念。
Promise的状态
Promise对象有三个状态:pending,fulfilled,rejected,MDN文档上对Promise对象状态变化过程用一幅图描述:

图中有几个小细节:
- 图中的fulfill和reject只是表示指向不同结果,而不是指一个过程,在到达
fulfilled,rejected状态前promise都处在pending状态。 settled包括了fulfilled和rejected。- promise只会在
pending,fulfilled,rejected三种状态下切换。 
resolved 和 unresolved
事情在现在看来都很美好,状态清晰,一目了然。然而,在各种教程中我们会看到这样一个状态:resolved,阮老师的ECMAScript 6 入门中直接把它当作了fulfilled状态:
Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。
但是MDN中的备注是这样写的:
你可能也会听到一个术语
resolved,它表示Promise对象处于settled状态,或者Promise对象被锁定在了调用链中。
嗯?记不记得上面提到settled状态包括fulfilled和rejected状态,那么他至少不能和fulfilled状态划等号吧?于是我又搜了搜,发现网上很多文章提到resolved这个词时,有人直接当作fulfilled状态,有人把它理解为complete(类似地,fulfilled是success,rejected自然就是error或者failure),不过更多人都是很含糊地引用了一下文档或者阮老师的文章。
不过确实有人直接提出了这个问题:Promise的fulfill和resolve为啥要用两个词?,我着重看了贺师俊老师的回答:
因为 fulfill 和 resolve 是不同的。
resolve 只是表示这个 promise 已经确定了,比如 promise A 被 resolve 为 promise B,则 A 已经 resolved 但是并未 fulfilled 。
好吧,我承认我一开始看没看懂...
不过还好在备注那里MDN放出了一篇帮助理解的文章,Domenic Denicola 的 States and Fates,基本把这两个概念说清楚了,不过文中只有简单的文字描述,下面说一下我自己的理解。
state 和 fates
文章将Promise分得更细,分为了状态(state)和结果(fates,命运,原谅我粗浅的翻译)。
状态(state)就是上面提到的三种状态,需要稍微留意一下的是,文中提到settled不是一种Promise状态,只是一种语义上的便利,说白了就是描述Promise确定了而已。
结果(fates)分为resolved和unresolved,两种结果互斥。
- resolved,原文解释有点绕:
 
A promise is resolved if trying to resolve or reject it has no effect,当没办法去resolve或reject一个promise的时候,这个promise就是resolved的。
- unresolved,原文解释倒是很简单:非resolved的promise...... (:з」∠)
 
显而易见,只要理解了resolved的描述,自然就理解unresolved。首先先提一个Promise的概念,即当Promise的状态一旦改变,就永久保持该状态。所以什么时候没办法去resolve或reject一个promise对象呢?
- 处于
fulfilled和rejected状态的promise对象,因为他们已经无法改变状态,而resolve和reject只能对pending状态的promise有效。 - 处于
pending状态的promise对象也有可能处于resolved,当promise对象被'锁定'在另外一个promise对象或者一个非即时返回的thenable函数中时,也就是上面贺老师提到的promise A 被 resolve 为 promise B这种情况,为了帮助理解,下面用代码举个例子。 
说明:Chrome(57.0.2987.133)打印promise对象的时候,[[PromiseStatus]]有三个值:pending,resolved,rejected,这里的resolved状态就是指fulfilled状态,和我们要说明的resolved没有关系,在firefox(49.0.1)中,[[PromiseStatus]]三个值和标准相同:pending,fulfilled,rejected。为了避免混淆,用firefox做测试
先上一个简单的代码:
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对象状态为fulfilled。再来看第二例子,在resolve方法中新建了一个Promise对象:
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了,理应变为fulfilled状态,但是他被'锁定'在了一个新的Promise对象中,所以状态没有立刻改变并执行onfulfilled方法,而是依然处于pending状态,但是很明显的是,他的最终结果(这里可以体会到称为fate的原因,有种宿命的味道)就是fulfilled状态,此时的p1不能再resolve或reject。再过了两秒后新Promise对象resolve,p1执行then(),状态变为fulfilled,打印的值也变成了new Promise resolve,而不是p1 resolve。此时打印出的p1的状态就是fulfilled。
到此,处于pending状态的promise对象也有可能处于resolved情况就很清楚了,至于unresolved,就是promise可以被resolve或reject的时候,此时promise对象一定处于pending状态且没有被resolve或reject为其他Promise对象 / 非即时返回的thenable函数。而反过来,处于pending状态的promise对象不一定是unresolved。
小结
到这里Promise对象的状态和resolved的概念差不多都清楚了,这篇文章也是我个人理解过程的一个记录。不过参考到的文章不多,文中的解释可能并不是很准确,所以在这里贴出来,希望能看看其他人的理解。
一些闲话
说起来,这篇文章离我上一篇文章已经很久了,真是光阴似箭,岁月......算了,还是不感慨了。现在工作确实没有在学校那会儿充足的时间和精力,总结还是有不少,大部分都在个人的笔记里,没有贴到博客。有些觉得总结份量不够,有些觉得个人的理解不深,不敢随意贴出来。不过在学习一些稍微深入一点的概念的时候,总觉得网上的一些资料并不是很全面和客观,人云亦云的东西太多,自己的理解也是七七八八。所以希望能够贴出来和大家交流,防止自己闭门造车,后续如果工作时间允许,会发一些这样的文章,对前端一些比较重要的知识点深入理解。
本文来源:JuFoFu
本文地址:http://www.cnblogs.com/JuFoFu/p/5140302.html
参考文档:
Domenic Denicola . States and Fates
阮一峰 . Promise 对象
MDN . Promise
ES6 Promise 状态解惑的更多相关文章
- 通过 ES6 Promise 和 jQuery Deferred 的异同学习 Promise
		
Deferred 和 Promise ES6 和 jQuery 都有 Deffered 和 Promise,但是略有不同.不过它们的作用可以简单的用两句话来描述 Deffered 触发 resolve ...
 - ES6 Promise 接口
		
构造函数 new Promise(function(resolve, reject){}); 构造函数接受一个函数(executor)作为参数,该函数在返回 Promise 实例之前被调用.函数的两个 ...
 - ES6 Promise 对象
		
Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Pro ...
 - Es6 Promise 用法详解
		
Promise是什么?? 打印出来看看 console.dir(Promise) 这么一看就明白了,Promise是一个构造函数,自己身上有all.reject.resolve这几个眼熟的方 ...
 - ES6 Promise 全面总结
		
转载:点击查看原文 ES6 Promise对象 ES6中,新增了Promise对象,它主要用于处理异步回调代码,让代码不至于陷入回调嵌套的死路中. @-v-@ 1. Promise本质 Promise ...
 - ES6 Promise  异步操作
		
最近越来越喜欢与大家进行资源分享了,并且及时的同步到自己的园子内,为什么呢? 一.小插曲(气氛搞起) 在上个月末,由于领导的高度重视(haha,这个高度是有多高呢,185就好了),走进了公司骨干员工的 ...
 - 解析ES6 Promise
		
ES6 Promise 概念之类的,大概读者都应该有所知道,接下来我们直入终点. 先让我们来看看什么是Promise吧,他是一个object,类,arry,function? 首先,学习它的时候应该讲 ...
 - jquery Promise和ES6 Promise的区别
		
1. Deferred对象有resolve和reject方法,可以直接修改状态 jquery用Deferred实现了Promise规范,Deferred与ES6 Promise的最大区别是: Defe ...
 - ES6 Promise对象then方法链式调用
		
then()方法的作用是Promise实例添加解决(fulfillment)和拒绝(rejection)状态的回调函数.then()方法会返回一个新的Promise实例,所以then()方法后面可以继 ...
 
随机推荐
- 最简单的 RabbitMQ 监控方法 - 每天5分钟玩转 OpenStack(158)
			
这是 OpenStack 实施经验分享系列的第 8 篇. 先来看张图:这是 Nova 的架构图,我们可以看到有两个组件处于架构的中心位置:数据库和Queue.数据库保存状态信息,而几乎所有的 nova ...
 - css中的那些布局
			
因为最近心血来潮,就总结了一下css中的几种常见的多列布局. 两列自适应布局 两列自适应布局算是css布局里面最基础的一种布局了,不少网站在使用. 这种布局通常是左侧固定,右边自适应,当然也有反过来的 ...
 - php实现留言板功能
			
这个小小的留言板功能适合班级内或者公司内部之间的讨论,对话和留言,非常的方便,更重要的是无需网络,对于公司管理层来说是非常乐于常见的, 下面是这个留言板的写法: 1 首先是登录页面: <form ...
 - layer弹出层框架alert与msg详解
			
ayer至今仍作为layui的代表作,她的受众广泛并非偶然,而是这五年多的坚持,不断完善和维护.不断建设和提升社区服务,使得猿们纷纷自发传播,乃至于成为今天的Layui最强劲的源动力.目前,layer ...
 - 雪花降落CAEmitterLayer粒子效果
			
CAEmitterLayer 实现雪花效果 首先需要导入#import <QuartzCore/QuartzCore.h> /**在iOS 5中,苹果引入了一个新的CALayer子 ...
 - 详解JDBC连接数据库
			
一.概念 1. 为了能让程序操作数据库,对数据库中的表进行操作,每一种数据库都会提供一套连接和操作该数据库的驱动,而且每种数据库的驱动都各不相同,例如mysql数据库使用mysql驱动,oracle数 ...
 - 【收集】sql查询统计,周,月,年
			
昨天 select * from tb where datediff(day, 时间字段 ,getdate()) = 1 今天 select * from tb where datediff(day, ...
 - 无线同步模块SYN1000在电力监测相位测量领域的应用方案
			
在电力监测领域,出于安全考虑,有些系统不得不采用无线通信的方式,在这样一个无线通信的应用系统,该如何来控制多个设备进行同步采样,以期提高相位角的测量精度,是一个不小的难题. 很多技术人员习惯性的采用无 ...
 - SQL server 数据库(视图、事物、分离附加、备份还原))
			
ql Server系列:视图.事物.备份还原.分离附加 视图是数据库中的一种虚拟表,与真实的表一样,视图包含一系列带有名称的行和列数据.行和列数据用来自定义视图的查询所引用的表,并且在引用视图时动态 ...
 - Nginx uWSGI  web.py 站点搭建
			
一.安装nginx 在安装nginx前,需要先装nginx的依赖包. 1.如果没有yum则先安装yum 删除原有的yum rpm -aq|grep yum|xargs rpm -e --node ...