Promise基本概念
关Promise 的使用,在《JavaScript Promise迷你书(中文版)》这本书里面讲解的非常的详细,这边就不在重复,下面只列出来一些比较重要的点和一些比较忽略的地方。
以为promise的知识在迷你书里面看过就记住了,过了一段时间之后发现好多又忘了,这里结合阮老师的ES6-Promise对象重新将Promise的重点给总结一下,放到这篇文档里面,以后方便查阅。
promise定义及特点
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise
对象。
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise
对象有以下两个特点。
(1)对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。Promise
也有一些缺点。首先,无法取消Promise
,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise基本实例
创建promise对象的流程如下所示。
new Promise(fn)
返回一个promise对象在
fn
中指定异步等处理处理结果正常的话,调用
resolve(处理结果值)
处理结果错误的话,调用
reject(Error对象)
promise对象的处理过程只有两种情况, resolve和reject
有一种情况:p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。
对于这种情况,promise的解决方案是:这时p1
的状态就会传递给p2
,也就是说,p1
的状态决定了p2
的状态。如果p1
的状态是pending
,那么p2
的回调函数就会等待p1
的状态改变;如果p1
的状态已经是resolved
或者rejected
,那么p2
的回调函数将会立刻执行。阮老师Promise对象里面有关于这种情况的一个例子。
promise结束状态
调用resolve
或reject
并不会终结 Promise 的参数函数的执行。
promise方法链
finally()
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
finally
方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
Promise.all()
Promise.all
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
上面代码中,Promise.all
方法接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。(Promise.all
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
p
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
注意事项:
1、如果作为参数的 Promise 实例,自己定义了
catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。2、如果其中的某一个promise实例
p1或p2或p3
没有自己的catch
方法,就会调用Promise.all()
的catch
方法。
Promise.race()
Promise.race
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
上面代码中,只p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
有时候设定了一个时间限制,如果规定时间内
p1 p2 p3
都没有改变状态,那p的状态变成reject
Promise.resolve()
Promise.resolve
方法可以将现有对象转为 Promise 对象。
Promise.resolve
方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve
将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable
对象
thenable
对象指的是具有then
方法的对象,Promise.resolve
方法会将这个对象转为 Promise 对象,然后就立即执行thenable
对象的then
方法。
(3)参数不是具有then
方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then
方法的对象,则Promise.resolve
方法返回一个新的 Promise 对象,状态为resolved
。
4)不带有任何参数
Promise.resolve
方法允许调用时不带参数,直接返回一个resolved
状态的 Promise 对象。
promise的返回
专栏: 每次调用then都会返回一个新创建的promise对象 {#then-return-new-promise}
从代码上乍一看,aPromise.then(...).catch(...)
像是针对最初的aPromise
对象进行了一连串的方法链调用。
然而实际上不管是then
还是catch
方法调用,都返回了一个新的promise对象
Promise.try()
对于不知道或者不想区分的通过或者异步操作,但是想用promise处理,以前常用的方法有两种,一种是使用async
函数,
第二种写法是使用new Promise()。
所以提出一个提案,Promise.try()
参考
Last updated