ES6 Promise对象
Promise对象
含义
Promise是异步编程的一种解决方案,最早由社区提出和实现,ES6在次基础上统一了用法并且提供了Promise对象。
所谓的Promise简单来说就是一个容器:里面保存着某个未来才会结束的事件的结果。从语法上说:Promise是一个对象,从它可以获取异步操作的消息。
Promise对象由两个特点:
- 对象的状态不受外界影响,只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这种状态;
- 一旦状态发生了改变,就不会再变,任何时候都可以得到这个结果。
因此:有了Promise,就可以将异步操作以同步的流程表达出来,避免了蹭蹭嵌套的回调函数。此外,Promise还提供了统一的接口,使得控制异步操作更加容易。
但是Promise也存在缺点:例如一旦创建就会立即执行,无法中途取消,其次,如果不设置回调函数,Promise内部会抛出异常,不会反应到外部。最后,当处于Pending状态的时候,无法得知目前进展到哪一个阶段。
基本用法
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
1 |
|
Promise新建后会立即执行
1 |
|
Promise.prototype.then()
then
方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。该方法返回的是一个新的Promise实例。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
采用链式的then
,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
1 |
|
如果使用箭头函数,可以将上面代码进一步简化。
1 |
|
Promise.prototype.catch()
用于指定发生错误时的回调函数。
1 |
|
如果Promise状态已经变成了Resolved,再抛出错误就是无效的。
1 |
|
Promise对象错误具有”冒泡“性质,会一直向后传递,直到被捕获为止。也就是说:错误总会被下一个catch
语句捕获。
1 |
|
与传统的try/catch
代码块不同的是,如果没有使用catch
方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码。但是Chrome不遵守这个规则,还是会抛出异常。好在Node.js提供了一个unhandledRejection
事件,专门监听未捕获的reject
错误。
1 |
|
catch
方法中还可以继续抛出异常。例如下面的代码:第二个catch
方法用来捕获,前一个catch
方法抛出错误。
1 |
|
Promise.all()
Promise.all
方法用于将多个Promise实例,包装成一个新的Promise实例。语法如下:
1 |
|
例子如下:只有这6个实例的状态都变成了fulfilled
,或者其中有一个状态变成了rejected
,才会调用Promise.all
方法后面的回调函数。
1 |
|
再例如下面这个例子:只有booksPromise
和userPromise
的结果都返回了,才会触发pickTopRecommentations
这个回调函数。
1 |
|
Promise.race()
跟上面的作用一样,将多个Promise实例合成一个新的Promise实例。
1 |
|
上面的例子中:只要三个状态有其中一个率先改变,新对象的状态就跟着一起改变。率先改变的Promise实例的返回值就是新Promise实例的回调函数的输入。
下面提供一个实例:如果指定时间内没有获得结果,就将Promise的状态变为reject
,否则就为resolve
1 |
|
Promise.resolve()
有时需要将现有对象转为Promise对象,Promise.resolve()方法就起这个作用。
1 |
|
Promise.resolve
方法的参数可以分为4种情况。
- 参数是一个Promise实例:不做任何修改,原封不动返回实例
- 参数是一个thenable对象:将该对象转换为Promise对象,然后立即执行
thenable
对象的then
方法; - 参数不是具有then方法的对象,或根本就不是对象:返回一个新的
Promise
对象,状态为Resolved
; - 不带有任何参数:直接返回一个状态为
Resolved
的Promise对象;
Promise.reject()
也会返回一个新的Promise实例,该实例的状态为rejected
。其参数用法和Promise.resolve()
方法完全一致;
两个有用的附加方法
done()
提供一个done
方法,总是处于回调链的尾端,保证抛出任何可能出现的错误
finally()
用于指定不管Promise对象最后状态如何,都会执行的操作。与Done
方法最大的区别,接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。
应用
加载图片
我们可以将图片加载写成一个Promise,一旦加载完成,Promise
的状态就发生变化;
Generator函数结合Promise
使用Generator函数管理函数流程,遇到异步操作的时候,通常返回一个Promise
对象;
Promise.try()
实际开发中还遇到一种情况:不知道或者不想区分函数f是同步还是异步,但还是想用Promise来处理。
实际开发中提供了两种写法来实现这种效果:
1 |
|
需要注意的是async () => f()
会吃掉f()
抛出的异常,因此需要使用promise.catch
方法来捕获异常;
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!