ES6中Promise的使用方法实例总结


Posted in Javascript onFebruary 18, 2020

本文实例讲述了ES6中Promise的使用方法。分享给大家供大家参考,具体如下:

在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的。

但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回调函数里,这样一层嵌一层,最终形成回调地狱。

$.get('/login.php', function (login) {
  $.get('/user.php', function (user) {
    $.get('/info.php', function (info) {
      //代码就这样一层嵌一层,不够直观,维护也麻烦
    });
  });
});

为了解决这种问题,ES6中就提供了Promise方法来解决这种问题。

Promise是一个构造函数,通过它,我们可以创建一个Promise实例对象。

let p = new Promise(function (resolve, reject) {
  setTimeout(() => {
    console.log('OK');
    resolve('OK');
  }, 1000);
});

Promise构造函数接受一个函数作为参数,这个函数有两个参数,resolve和reject。

resolve函数是将Promise的状态设置为fulfilled(完成),reject函数是将Promise的状态设置为rejected(失败)。

上述代码,我们并没有进行任何调用,当运行时,间隔1秒后输出了'OK'。所以这里需要注意,我们通常使用Promise时,需要在外层再包裹一层函数。

let p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log('OK');
      resolve('OK');
    }, 1000);
  });
};
p();

上面的代码p();返回的是一个Promise实例对象,Promise对象上有 then() , catch() , finally() 方法。

then方法有两个参数,onFulfilled和onRejected,都是函数。

onFulfilled用于接收resolve方法传递过来的数据,onRejected用于接收reject方法传递过来的数据。

let p = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve('OK');
      } else {
        reject('ERR');
      }
    }, 1000);
  });
};
p().then(function (data) {
  console.log('fulfilled', data);
}, function (err) {
  console.log('rejected', err);
});

then()方法总是会返回一个Promise实例,这样我们就可以一直调用then()。

在then方法中,你既可以return 一个具体的值 ,还可以return 一个Promise对象。

如果直接return的是一个数据,那then方法会返回一个新Promise对象,并以该数据进行resolve。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve(1);
  });
};
p().then(function (data) {
  console.log(`第 ${data} 次调用`);
  //注意这里直接返回的值
  //then会创建一个新的Promise对象,并且以返回的值进行resolve
  //那么该值会被下面的then方法的onFulfilled回调拿到
  return ++data;
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return ++data;
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return ++data;
});

如果返回的是一个Promise对象,请看下面代码。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve(1);
  });
};
p().then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
}).then(function (data) {
  console.log(`第 ${data} 次调用`);
  return new Promise(function (resolve, reject) {
    resolve(++data);
  });
});

其实效果与直接返回值的是一样的。

即然then()可以进行链式操作,那我们最早之前的回调地狱写法,就可以通过它进行改进了。

function login() {
  return new Promise(function (resolve, reject) {
    $.get('/login.php', function (result) {
      resolve(result);
    });
  });
}
function user(data) {
  return new Promise(function (resolve, reject) {
    $.get('/user.php', function (result) {
      resolve(result);
    });
  });
}
function info(data) {
  return new Promise(function (resolve, reject) {
    $.get('/info.php', function (result) {
      resolve(result);
    });
  });
}
login().then(function (data) {
  console.log('处理login');
  //把login异步处理获取的数据,传入到下一个处理中。
  return user(data);
}).then(function (data) {
  console.log('处理user');
  //把user异步处理获取的数据,传入到下一个处理中。
  return info(data);
}).then(function (data) {
  console.log('处理info');
});

这样修改后,回调地狱层层嵌套的结构就变的清晰多了。上述代码是伪代码。

Promise对象还有一个catch方法,用于捕获错误,该方法与 then(null, onRejected) 等同,是一个语法糖。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve('开始');
  });
};
p().then(function (data) {
  console.log('1');
  return new Promise(function (resolve, reject) {
    reject('错误1');
  });
}).then(function (data) {
  console.log('2');
  return new Promise(function (resolve, reject) {
    reject('错误2');
  });
}).then(function (data) {
  console.log('3');
  return new Promise(function (resolve, reject) {
    reject('错误3');
  });
}).catch(function (reason) {
  console.log(reason);
});

注意,一旦操作中有错误发生,则会进入到catch中,后面的操作将不再执行。

Promise对象内部自带了try catch,当代码运行时错误,会自动以错误对象为值reject,并最终被catch捕获。

let p = function () {
  return new Promise(function (resolve, reject) {
    resolve('开始');
  });
};
p().then(function (data) {
  //注意这里打印了一个未定义的变量
  console.log(a);
}).catch(function (reason) {
  //这里会捕获到错误
  console.log('rejected');
  console.log(reason);
});

Promise还提供了,all(),race(),reject(),resolve()等在构造函数上的方法,调用这些方法并不需要实例化对象。

all()方法,可以让我们并行的执行异步操作,直到所有操作完成了,才执行回调。

function fn1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn1');
    }, 1000);
  });
}
function fn2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn2');
    }, 2000);
  });
}
function fn3() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn3');
    }, 3000);
  });
}
//all会等待所有操作完成,会把所有操作的结果放到一个数组中,传给then。
Promise.all([fn1(), fn2(), fn3()]).then(function (data) {
  console.log(data);
});

race()方法是谁先处理完,就以谁为准,把最先处理完的结果传给then。

function fn1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn1');
    }, 1000);
  });
}
function fn2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn2');
    }, 2000);
  });
}
function fn3() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve('fn3');
    }, 3000);
  });
}
//race是以谁先处理完,就以谁为准,fn1最先处理完,那fn1的结果会传给then
//注意这里fn2和fn3还是会执行,不过不会进入then了
Promise.race([fn1(), fn2(), fn3()]).then(function (data) {
  console.log(data);
});

reject()方法,返回一个带有拒绝原因reason参数的Promise对象。

// Promise.reject('错误')
// 等同于
// new Promise(function(resolve, reject) {
//   reject('错误');
// });
let p = Promise.reject('错误');
p.then(function (data) {
}).catch(function (reason) {
  console.log(reason);
});

resolve()方法,根据传入的值返回一个Promise对象。

//如果传入的参数是普通值,则返回一个新Promise对象,并以该值resolve
let p1 = Promise.resolve('OK');
p1.then(function (data) {
  console.log(data);
});
//如果传入的参数是一个Promise对象,则原封不动的返回该Promise对象
let obj = new Promise(function (resolve, reject) {
  resolve('我是Promise对象');
});
let p2 = Promise.resolve(obj);
p2.then(function (data) {
  console.log(data);
  console.log(p2 === obj);
});
//如果传入的参数是一个thenable对象(带有then方法),
//会转换成Promise对象,并执行thenable对象的then方法
let then = {
  then(resolve, reject) {
    resolve('我是thenable对象');
  }
}
let p3 = Promise.resolve(then);
p3.then(function (data) {
  console.log(data);
});
//如果什么参数都不传入,则返回状态为resolved的Promise对象
let p4 = Promise.resolve();
p4.then(function (data) {
  console.log(data);
}).catch(function (reason) {
  console.log(reason);
});

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
解放web程序员的输入验证
Oct 06 Javascript
javascript模拟实现ajax加载框实例
Oct 15 Javascript
node.js中的console.assert方法使用说明
Dec 10 Javascript
node.js中的fs.write方法使用说明
Dec 15 Javascript
PHP实现的各种中文编码转换类分享
Jan 23 Javascript
JS实现的5级联动Select下拉选择框实例
Aug 17 Javascript
简单实现jQuery进度条轮播实例代码
Jun 20 Javascript
浅谈js在html中的加载执行顺序,多个jquery ready执行顺序
Nov 26 Javascript
bootstrap快速制作后台界面
Dec 05 Javascript
JS图片轮播与索引变色功能实例详解
Jul 06 Javascript
Vue底层实现原理总结
Feb 17 Javascript
node.js中ws模块创建服务端和客户端,网页WebSocket客户端
Mar 06 Javascript
React中获取数据的3种方法及优缺点
Feb 18 #Javascript
JavaScript canvas绘制渐变颜色的矩形
Feb 18 #Javascript
JavaScript canvas绘制折线图
Feb 18 #Javascript
node+multer实现图片上传的示例代码
Feb 18 #Javascript
JavaScript canvas绘制圆弧与圆形
Feb 18 #Javascript
javascript中的with语句学习笔记及用法
Feb 17 #Javascript
JS实现百度搜索框关键字推荐
Feb 17 #Javascript
You might like
php parse_str() 函数的定义和用法
2016/05/23 PHP
thinkPHP多域名情况下使用memcache方式共享session数据的实现方法
2016/07/21 PHP
phpStudy2016 配置多个域名期间遇到的问题小结
2017/10/19 PHP
js判断请求的url是否可访问,支持跨域判断的实现方法
2016/09/17 Javascript
js document.getElementsByClassName的使用介绍与自定义函数
2016/11/25 Javascript
详解springmvc 接收json对象的两种方式
2016/12/06 Javascript
微信小程序图表插件(wx-charts)实例代码
2017/01/17 Javascript
JS扩展String.prototype.format字符串拼接的功能
2018/03/09 Javascript
vue-swiper的使用教程
2018/08/30 Javascript
jQuery使用$.extend(true,object1, object2);实现深拷贝对象的方法分析
2019/03/06 jQuery
在Vue项目中使用Typescript的实现
2019/12/19 Javascript
jQuery实现可以扩展的日历
2020/12/01 jQuery
[09:40]DAC2018 4.5 SOLO赛 MidOne vs Miracle
2018/04/06 DOTA
[01:36]极致酷炫!TI9典藏宝瓶+撼地者至宝展示
2019/06/11 DOTA
利用Python为iOS10生成图标和截屏
2016/09/24 Python
matplotlib 纵坐标轴显示数据值的实例
2018/05/25 Python
python3.x 将byte转成字符串的方法
2018/07/17 Python
Ubuntu18.04下python版本完美切换的解决方法
2019/06/14 Python
python Tensor和Array对比分析
2020/01/08 Python
python实现贪吃蛇游戏源码
2020/03/21 Python
Python tkinter实现简单加法计算器代码实例
2020/05/13 Python
Python实现UDP程序通信过程图解
2020/05/15 Python
Python调用REST API接口的几种方式汇总
2020/10/19 Python
法国珠宝店:CLEOR
2017/01/29 全球购物
加拿大时尚潮流大码女装购物网站:Addition Elle
2018/04/02 全球购物
J2EE相关知识面试题
2013/08/26 面试题
音乐专业应届生教师求职信
2013/11/04 职场文书
门诊手术室工作制度
2014/01/30 职场文书
个人实习生的自我评价
2014/02/16 职场文书
幼儿园优秀班主任事迹材料
2014/05/14 职场文书
多媒体编辑专业毕业生求职信
2014/06/13 职场文书
鼓舞士气的口号
2014/06/16 职场文书
捐款感谢信
2015/01/20 职场文书
MySQL 外键约束和表关系相关总结
2021/06/20 MySQL
MySQL如何快速创建800w条测试数据表
2022/03/17 MySQL
Go 内联优化让程序员爱不释手
2022/06/21 Golang