Promise 相信写前端的同学都不陌生, 本意是承诺, 答应完成某事. promise 主要用于异步计算. 可以将异步操作队列化, 按照期望的顺序执行, 返回符合预期的结果. 还可以在对象之间传递和操作 promise, 帮助我们处理队列.
和其他异步调用的优点在于:
promise 是一个对象, 对象和函数的区别就是对象可以保存状态, 函数不可以 (闭包除外).
并未剥夺函数 return 的能力, 因此无需层层传递 callback, 进行回调获取数据.
代码风格, 容易理解, 便于维护.
多个异步等待合并便于解决.
promise 有三个状态:
1,pending[待定] 初始状态
2,fulfilled[实现] 操作成功
3,rejected[被否决] 操作失败
当 promise 状态发生改变, 就会触发 then() 里的响应函数处理后续步骤;
promise 状态一经改变, 不会再变.
Promise 对象的状态改变, 只有两种可能:
从 pending 变为 fulfilled
从 pending 变为 rejected.
这两种情况只要发生, 状态就凝固了, 不会再变了.
所以我们可以生成这样的链式调用 new Promise().then().then().catch()
我们来看下 Promise 可以怎么处理异常:
第一种 catch+then
- //catch+then
- new Promise(resolve => {
- throw new Error('this is a error')
- }).catch(err=>{
- console.error('catch+then: I catch',err)
- }).then(res=>{
- console.log('222')
- }).catch(err=>{
- console.error('catch+then: I catch2',err)
- })
image.PNG
可以看出 catch 返回的 Promise 的状态也是 resolved, 可以继续执行 then.
第二种 then
- //then
- new Promise(()=>{
- console.log('start...')
- throw new Error('this is a error')
- }).catch(err=>{
- console.error('i catch:', err)
- throw new Error('this is another error')
- }).then(()=>{
- console.log('test')
- }).then(()=>{
- console.log('test2')
- }).catch(err=>{
- console.error('I also catch',err)
- })
image.PNG
可以看出抛出错误变为 rejected 状态, 所以绕过两个 then 直接跑到最下面的 catch.
Promise.all(p1,p2...), 等待 p1,p2 都完成了返回.
Promise.race(p1,p2,..), 只要有一个完成, 就返回.
可用于异步操作和定时器放在一起, 如果定时器先触发, 就认为超时, 告知用户;
接下来, 我们来挑战下 Promise 经典的四道题:
- 1. doSomething().then(function () {
- return doSomethingElse();
- });
- 2. doSomething().then(function () {
- doSomethingElse();
- }).then(final);
- 3. doSomething().then(doSomethingElse()).then(final);
- 4. doSomething().then(doSomethingElse);
第一个: 先执行 doSomething(), 然后再执行 doSomethingElse(), 然后再往下执行.
第二个: 没有 return, 所以函数体中不返回新的 promise 实例, 所以是两个队列, 在 doSomething 执行完后, final 和 doSomethingElse 同时执行.
第三个: 函数体中是 doSomethingElse(), 是一个可执行的 promise 实例, 可以和 doSomething 一起执行, 然后它的结束状态不管, final 函数会在 doSomething 结束后执行.
第四个: 跟平时见到的一样, resolve 和 reject, 按顺序执行.
综上, Promise 感觉和 java 中的 builder 构造器一样, 又有点像适配器模式那样, 将复杂的请求分而治之, 无疑是前端开发的一大利器.
来源: http://www.jianshu.com/p/c883156e5f79