说明

Promise是一个构造函数,自己身上有call、resolve、reject,原型上有then、catch等方法。
Promise 对象有以下两个特点。

  1. 对象的状态不受外界影响。有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。

这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

开始

初步理解

  1. var promise = new Promise(function(resolve, reject) {
  2. setTimeout(function(){
  3. console.log('完成')
  4. resolve('随便什么东西')
  5. }, 2000)
  6. })

类似这样,Promise的构造函数接受一个参数:函数。并且会传入两个参数resolve、reject,用来表示成功或者失败。

一般情况会把promise放在一个函数中,当函数调用时候才会执行promise的操作。

  1. function runAsync(){
  2. var p = new Promise(function(resolve, reject){
  3. //做一些异步操作
  4. setTimeout(function(){
  5. console.log('执行完成');
  6. resolve('随便什么数据');
  7. }, 2000);
  8. });
  9. return p;
  10. }
  11. runAsync().then(function(data){
  12. console.log(data);
  13. //后面可以用传过来的数据做些其他操作
  14. //......
  15. });

表面上看Promise只是简化层层的回调写法,实质上,Promise的精髓是状态

链式操作的用法

  1. function runAsync1(){
  2. var p = new Promise(function(resolve, reject){
  3. //做一些异步操作
  4. setTimeout(function(){
  5. console.log('异步任务1执行完成');
  6. resolve('随便什么数据1');
  7. }, 1000);
  8. });
  9. return p;
  10. }
  11. function runAsync2(){
  12. var p = new Promise(function(resolve, reject){
  13. //做一些异步操作
  14. setTimeout(function(){
  15. console.log('异步任务2执行完成');
  16. resolve('随便什么数据2');
  17. }, 2000);
  18. });
  19. return p;
  20. }
  21. function runAsync3(){
  22. var p = new Promise(function(resolve, reject){
  23. //做一些异步操作
  24. setTimeout(function(){
  25. console.log('异步任务3执行完成');
  26. resolve('随便什么数据3');
  27. }, 2000);
  28. });
  29. return p;
  30. }
  1. runAsync1()
  2. .then(function(data){
  3. console.log(data);
  4. return runAsync2();
  5. })
  6. .then(function(data){
  7. console.log(data);
  8. return runAsync3();
  9. })
  10. .then(function(data){
  11. console.log(data);
  12. });

Promise总结 - 图1

  1. runAsync1()
  2. .then(function(data){
  3. console.log(data);
  4. return runAsync2();
  5. })
  6. .then(function(data){
  7. console.log(data);
  8. return '直接返回数据'; //这里直接返回数据
  9. })
  10. .then(function(data){
  11. console.log(data);
  12. });

Promise总结 - 图2

reject的用法

reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。

then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调。

  1. var promise = new Promise((resolve, reject) => {
  2. reject('失败')
  3. })
  4. promise.then((data) =>{
  5. console.log('success:' + data)
  6. },(reason) => {
  7. console.log('error:' + reason);
  8. })

catch的用法

Promise除了then还有catch方法,他和then的第二个参数一样,用来指定reject的回调。但是他还有一个作用:当在执行resolve的回调时候,如果出现异常那么js不会卡死,而是会进入到catch方法中。

当catch上面有处理reject的函数时候,会一级一级的处理,而不是直接跳到catch中。

  1. function getNumber(){
  2. var p = new Promise(function(resolve, reject){
  3. //做一些异步操作
  4. setTimeout(function(){
  5. var num = Math.ceil(Math.random()*10); //生成1-10的随机数
  6. if(num<=5){
  7. resolve(num);
  8. }
  9. else{
  10. reject('数字太大了');
  11. }
  12. }, 2000);
  13. });
  14. return p;
  15. }
  16. getNumber()
  17. .then(function(data){
  18. console.log(data);
  19. console.log(somedata); //此处的somedata未定义
  20. }).then((data) =>{
  21. console.log('success:' + data)
  22. },(reason) => {
  23. console.log('error:' + reason);
  24. })
  25. .catch(function(reason){
  26. console.error(reason);
  27. });

all的用法

Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

  1. Promise
  2. .all([runAsync1(), runAsync2(), runAsync3()])
  3. .then(function(results){
  4. console.log(results);
  5. });

Promise总结 - 图3

race的用法

all => 谁跑的慢,以谁为准执行回调

race => 谁跑的快,以谁为准执行回调

  1. Promise
  2. .race([runAsync1(), runAsync2(), runAsync3()])
  3. .then(function(results){
  4. console.log(results);
  5. });

Promise总结 - 图4
在then里面的回调开始执行时,runAsync2()和runAsync3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。

race的应用场景

  1. function requestImg(){
  2. var p = new Promise(function(resolve, reject){
  3. var img = new Image();
  4. img.onload = function(){
  5. resolve(img);
  6. }
  7. img.src = 'xxxxxx';
  8. });
  9. return p;
  10. }
  11. //延时函数,用于给请求计时
  12. function timeout(){
  13. var p = new Promise(function(resolve, reject){
  14. setTimeout(function(){
  15. reject('图片请求超时');
  16. }, 5000);
  17. });
  18. return p;
  19. }
  20. Promise
  21. .race([requestImg(), timeout()])
  22. .then(function(results){
  23. console.log(results);
  24. })
  25. .catch(function(reason){
  26. console.log(reason);
  27. });

Promise总结 - 图5

finally

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

  1. promise
  2. .then(result => {···})
  3. .catch(error => {···})
  4. .finally(() => {···});

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。

finally本质上是then方法的特例。

Promise的异常捕获方式

在Promise的构造体内进行错误处理

  1. var promise=new Promise(function(resolve,reject){
  2. try {
  3. throw new Error('test');
  4. }catch(e){
  5. reject(e)
  6. }
  7. })

通过Promise.prototype.catch来进行错误处理

  1. var promise=new Promise(function(resolve,reject){
  2. reject(new Error('test'));
  3. })
  4. promise.catch(function(e){
  5. //something to deal with the error
  6. console.log(e)
  7. })

catch方面里面还可以再抛错误,这个错误会被后面的catch捕获

  1. var promise=new Promise(function(resolve,reject){
  2. reject(new Error('test1'))
  3. })
  4. promise.catch(function(e){
  5. console.log(e);
  6. throw new Error('test2')
  7. }).catch(function(e){
  8. console.log(e)
  9. })
  10. // Error : test1
  11. // Error : test2

Promise.all中的异常捕获

如果组成Promise.all的promise有自己的错误捕获方法,那么Promise.all中的catch就不能捕获该错误。

  1. var p1=new Promise(function(resolve,reject){
  2. reject(new Error('test1'))
  3. }).catch(function(e){
  4. console.log("由p1自身捕获",e);
  5. })
  6. var p2=new Promise(function(resolve,reject){
  7. resolve();
  8. })
  9. var p=Promise.all([p1,p2]);
  10. p.then(function(){
  11. }).catch(function(e){
  12. //在此处捕获不到p1中的error
  13. console.log(e)
  14. })
  15. //由p1自身捕获 Error: test1

在promise中无法被捕获的错误

在promise实例resolve之后,错误无法被捕获。

  1. var promise=new Promise(function(resolve,reject){
  2. resolve();
  3. throw new Error('test');//该错误无法被捕获
  4. })
  5. promise.then(function(){
  6. //
  7. }).then(function(e){
  8. console.log(e)
  9. })

支持

Promise总结 - 图6
Promise总结 - 图7

常见问题

参考

  1. ES6 Promise 用法讲解
  2. 总结一下ES6/ES7中promise、generator和async/await中的异常捕获方法
  3. Promise 对象 - ECMAScript6入门

总结