经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JSJS库框架 » JavaScript » 查看文章
ES6 Promise用法详解
来源:cnblogs  作者:活捉一只可爱的佩奇  时间:2018/9/30 10:57:07  对本文有异议

What is Promise?

Promise是一个构造函数,接受一个参数(Function),并且该参数接受两个参数resolve和reject(分别表示异步操作执行成功后的回调函数、执行失败后的回调函数)

  1. var p = new Promise(function(resolve, reject){
  2. setTimeout(function(){
  3. console.log('执行完成');
  4. resolve('成功了!');
  5. }, 2000);
  6. });

运行代码,2秒后输出“执行完成”。注意,这里只是new了一个对象,并没有调用它,所以我们用Promise时是包在一个函数中的,如下:

  1. function runAsync(){
  2.   var p = new Promise(function(resolve, reject){
  3.   setTimeout(function(){
  4.   console.log('执行完成');
  5.   resolve('成功了!');
  6.   }, 2000);
  7.   });
  8.   return p;
  9. }
  10. runAsync();

 

Pormise的优势:

1. 解决回调函数层层嵌套的问题:

(1) 有时我们需要进行一些有依赖关系的异步操作,比如有多个请求,后一个请求需要上一次请求的返回结果,过去常规的做法是使用callback层层嵌套,这样的代码可读性和维护性都很差,比如:

 

  1. firstAsync(function(data){
  2. //处理得到的 data 数据
  3. //....
  4. secondAsync(function(data2){
  5. //处理得到的 data2 数据
  6. //....
  7. thirdAsync(function(data3){
  8. //处理得到的 data3 数据
  9. //....
  10. });
  11. });
  12. });

 

(2) 使用Promise的话,代码就会变得扁平化,可读性更高了。比如:

  1. firstAsync()
  2. .then(function(data){
  3. //处理得到的 data 数据
  4. //....
  5. return secondAsync();
  6. })
  7. .then(function(data2){
  8. //处理得到的 data2 数据
  9. //....
  10. return thirdAsync();
  11. })
  12. .then(function(data3){
  13. //处理得到的 data3 数据
  14. //....
  15. });

 

2.  更好的进行错误捕捉:

(1) 使用callback嵌套,可能会造成无法捕捉异常、异常捕捉不可控等问题。比如:

 

  1. function fetch(callback) {
  2. setTimeout(() => {
  3. throw Error('请求失败')
  4. }, 2000)
  5. }
  6. try {
  7. fetch(() => {
  8. console.log('请求处理') // 永远不会执行
  9. })
  10. } catch (error) {
  11. console.log('触发异常', error) // 永远不会执行
  12. }
  13. // 程序崩溃
  14. // Uncaught Error: 请求失败

 

(2) 使用Promise的话,通过reject方法吧Promise的状态置为rejected,这样我们就可以在then方法中捕捉到,并且执行“失败”情况的回调。比如:

  1. function fetch(callback) {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. reject('请求失败');
  5. }, 2000)
  6. })
  7. }
  8. fetch()
  9. .then(
  10. function(data){
  11. console.log('请求处理成功!');
  12. console.log(data);
  13. },
  14. function(reason, data){
  15. console.log('触发异常!');
  16. console.log(reason);
  17. }
  18. );

同时,也可以在catch方法中处理reject回调。比如:

 

  1. function fetch(callback) {
  2. return new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. reject('请求失败');
  5. }, 2000)
  6. })
  7. }
  8. fetch()
  9. .then(
  10. function(data){
  11. console.log('请求处理成功!');
  12. console.log(data);
  13. }
  14. )
  15. .catch(function(reason){
  16. console.log('触发异常!');
  17. console.log(reason);
  18. });

 

 

在上面的代码中我们用到了Promise的then、catch方法,下面我们再来介绍一下Promise中常用的一些方法。

then方法:

then方法就是将原来使用callback回调的写法分离出来,在异步操作完成之后,使用链式调用的方法执行回调函数。

then方法包含三个参数:

  • 成功回调
  • 失败回调
  • 前进回调(规范没有要求实现前进回调)

返回一个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. runAsync1()
  22. .then(function(data){
  23. console.log(data);
  24. return runAsync2();
  25. })
  26. .then(function(data){
  27. console.log(data);
  28. return '直接返回数据'; //这里直接返回数据
  29. })
  30. .then(function(data){
  31. console.log(data);
  32. });
  33. /*
  34. 输出:
  35. 异步任务1执行完成
  36. 成功了1
  37. 异步任务2执行完成
  38. 成功了2
  39. 直接返回数据
  40. */
View Code

 

resolve方法:

该方法把Promise的状态置为完成态(Resolved),这是then方法就能捕捉到变化,并执行“成功”回调的方法。比如:

  1. //做饭
  2. function cook(){
  3. console.log('开始做饭。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('做饭完毕!');
  7. resolve('鸡蛋炒饭');
  8. }, 1000);
  9. });
  10. return p;
  11. }
  12. //吃饭
  13. function eat(data){
  14. console.log('开始吃饭:' + data);
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('吃饭完毕!');
  18. resolve('完成!');
  19. }, 2000);
  20. });
  21. return p;
  22. }

使用then链式调用:

  1. cook()
  2. .then(function(data){
  3. return eat(data);
  4. })
  5. .then(function(data){
  6. console.log(data);
  7. });
  8. //可以简写
  9. cook()
  10. .then(eat)
  11. .then(function(data){
  12. console.log(data);
  13. });
  14. /*
  15. 输出:
  16. 开始做饭。
  17. 做饭完毕!
  18. 开始吃饭:鸡蛋炒饭
  19. 吃饭完毕
  20. 完成!
  21. */

 

reject方法:

该方法把Promise的状态置为已失败(rejected),then方法捕捉到变化,并执行“失败”回调的方法。比如:

  1. //做饭
  2. function cook(){
  3. console.log('开始做饭。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('做饭失败!');
  7. reject('烧焦的米饭');
  8. }, 1000);
  9. });
  10. return p;
  11. }
  12. //吃饭
  13. function eat(data){
  14. console.log('开始吃饭:' + data);
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('吃饭完毕!');
  18. resolve('完成!');
  19. }, 2000);
  20. });
  21. return p;
  22. }
  23. cook()
  24. .then(eat, function(data){
  25. console.log(data + '没法吃!');
  26. })
  27. /*
  28. 输出:
  29. 开始做饭。
  30. 做饭失败!
  31. 烧焦的米饭没法吃!
  32. */

 

catch方法:

1. 和then方法的第二个参数reject方法用法一致,执行“失败”回调方法

 

  1. cook()
  2. .then(eat)
  3. .catch(function(data){
  4. console.log(data + '没法吃!');
  5. });

 

2. 当执行第一个参数resolve方法时,如果抛出了异常(代码错误),js不会卡死,而进入到catch方法中

  1. //做饭
  2. function cook(){
  3. console.log('开始做饭。');
  4. var p = new Promise(function(resolve, reject){ //做一些异步操作
  5. setTimeout(function(){
  6. console.log('做饭完毕!');
  7. resolve('鸡蛋炒饭');
  8. }, 1000);
  9. });
  10. return p;
  11. }
  12. //吃饭
  13. function eat(data){
  14. console.log('开始吃饭:' + data);
  15. var p = new Promise(function(resolve, reject){ //做一些异步操作
  16. setTimeout(function(){
  17. console.log('吃饭完毕!');
  18. resolve('完成!');
  19. }, 2000);
  20. });
  21. return p;
  22. }
  23. cook()
  24. .then(function(data){
  25. throw new Error('米饭被打翻了!');
  26. eat(data);
  27. })
  28. .catch(function(data){
  29. console.log(data);
  30. });
  31. /*
  32. 输出:
  33. 开始做饭。
  34. 做饭完毕!
  35. Error:米饭被打翻了!
  36. at:xxx.html
  37. */
还可以添加多个 catch,实现更加精准的异常捕获。比如:
  1. somePromise.then(function() {
  2. return a();
  3. }).catch(TypeError, function(e) {
  4. //If a is defined, will end up here because
  5. //it is a type error to reference property of undefined
  6. }).catch(ReferenceError, function(e) {
  7. //Will end up here if a wasn't defined at all
  8. }).catch(function(e) {
  9. //Generic catch-the rest, error wasn't TypeError nor
  10. //ReferenceError
  11. });

 

all方法:

该方法提供了并行执行异步操作的能力,在所有异步操作执行完毕之后才会进入到then方法中执行回调方法。

all方法接受一个数组,里面的值最终都返回一个Promise对象。all会把所有的异步操作的结果放到一个数组中传递给then方法。比如//切菜

  1. function cutUp(){
  2. console.log('开始切菜。');
  3. var p = new Promise(function(resolve, reject){ //做一些异步操作
  4. setTimeout(function(){
  5. console.log('切菜完毕!');
  6. resolve('切好的菜');
  7. }, 1000);
  8. });
  9. return p;
  10. }
  11. //烧水
  12. function boil(){
  13. console.log('开始烧水。');
  14. var p = new Promise(function(resolve, reject){ //做一些异步操作
  15. setTimeout(function(){
  16. console.log('烧水完毕!');
  17. resolve('烧好的水');
  18. }, 1000);
  19. });
  20. return p;
  21. }
  22. Promise
  23. .all([cutUp(), boil()])
  24. .then(function(results){
  25. console.log("准备工作完毕:");
  26. console.log(results);
  27. });
  28. /*
  29. 输出:
  30. 开始切菜。
    开始烧水。
  31. 切菜完毕!
  32. 烧水完毕!
  33. 准备工作完毕:
  34. ["切好的菜","烧好的水"]
  35. */

 

race方法:

race按字面意思是,竞赛/赛跑。与all不同的是,所有的异步操作中只要有一个异步操作完成,就立即执行then回调方法。比如:

  1. Promise
  2. .race([cutUp(), boil()])
  3. .then(function(results){
  4. console.log("准备工作完毕:");
  5. console.log(results);
  6. });
  7. /*
  8. 输出:
  9. 开始切菜。
  10. 开始烧水。
  11. 切菜完毕!
  12. 准备工作完毕:
  13. 切好的菜
  14. 烧水完毕!
  15. */

race 使用场景很多。比如我们可以用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作。比如:

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

上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑,结果如下:

  • 如果 5 秒内图片请求成功,那么便进入 then 方法,执行正常的流程。
  • 如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号