Promise是什么
- ECMAscript 6原生提供了Promise对象
- promise对象代表了未来将要发生的时间,用来传递异步操作的消息
为什么要用Promise
-
为了解决回调地狱
-
解决异步同步事件
- 回调地狱:在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱(即,一个函数作为参数需要依赖另一个函数执行调用)
-
回调地狱的代码观赏性差,且难以维护
Promise特点
-
对象的状态不受外界影响
-
Promise 对象代表一个异步操作,有三种状态:
- pending: 初始状态,不是成功或失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
-
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
-
-
一旦状态改变,就不会再变,任何时候都可以得到这个结果。
- Promise 对象的
*状态改变*
,只有两种可能:- 从 Pending 变为 Resolved
- 从 Pending 变为 Rejected。
- 只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果.
- Promise 对象的
缺点
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段
创建Promise
-
Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject
1
2
3
4
5
6
7var promise = new Promise(function(resolve, reject){
//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
//使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 250);
}); -
对于已经实例化过的 promise 对象可以调用 promise.then() / .catch()方法,传递 resolve 和 reject 方法作为回调
-
.then 方法返回的是一个新的 Promise 对象,因此可以采用链式写法
-
错误处理两种做法:
- .then(() => {}, () => {错误处理逻辑})
- .catch( () => {错误处理逻辑})(推荐)
1
promise.then(onFulfilled).catch(onRejected)
-
使用promise
1 | /** |
链式操作
1 | handlePromise() |
Promise.all
- all接收一个数组参数[p1,p2,p3],里面的值最终都算返回Promise对象
- 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
- 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数
- 应用场景:游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化
1 | Promise.all([promise_01(), promise_02(), handlePromise()]) |
Promise.race
- race接收一个数组参数[p1,p2,p3],里面的值最终都算返回Promise对象
- 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值
- 应用场景:用race给某个异步请求设置超时时间,并且在超时后执行相应的操作
1 | Promise.race([promise_01(), promise_02(), handlePromise()]) |
1 | //请求某个图片资源 |