浅谈JavaScript中promise的使用


Posted in Javascript onJanuary 11, 2017

阅读目录

  • 什么是Prmoise
  • Promise的使用

最近在看《你不知道的javascript中卷》,发觉作者花了基本一半的篇幅去讲异步和promise,觉得有必要总结一下。

其实本文的目的是想手写一个Promise的,无奈总结着总结着发觉篇幅有点长,因此只好一分为二,先介绍promise的用法,知道怎么用,我们才知道怎么写,所以把手写一个promise的任务放到了下一篇文章当中。

当然,网上有很多关于promise的文章,都可以参考参考,有误之处,欢迎之处。

什么是Prmoise

promise是ES6新增的一个特征,它已被列入ES6的正式规范中

Promise对象可以理解为一次执行的异步操作,使用promise对象之后可以使用一种链式调用的方式来组织代码;让代码更加的直观。也就是说,有了Promise对象,就可以将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数。

示例:未使用promise,回调必须层层嵌套

$.ajax(url1, function(data1){
 // do something...
 $.ajax(url2, function(data2){
 // do something...
 $.ajax(url3, function(data3){
 // do something...
 done(data3); // 返回数据
 })
 });
});

如果有多个嵌套,导致代码不够直观,而且如果几个操作之前没有前后顺序之分,需要等待上一个操作完成才可以进行下一个操作,造成不必要的等待

promise就是为了解决这些问题而产生的。

Promise对象的特点:

1、对象的状态不受外界影响。

Promise对象代表一个异步操作,有三种状态

  • pending(执行中)
  • Resolved(成功,又称Fulfilled)
  • rejected(拒绝)

其中pending为初始状态,fulfilled和rejected为结束状态(结束状态表示promise的生命周期已结束)。

promise只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.。

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。

Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected

pending->fulfilled,pending->rejected。

只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果

Promise对象的缺点:

1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。

2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

promise兼容性

浅谈JavaScript中promise的使用

除了IE这种古老的浏览器和一些低版本的安卓外,现代浏览器支持还是挺好的,所以我们可以在谷歌的控制台直接测试我们的代码

Promise的使用

先提前说明一下,下面的代码示例,都可以复制到谷歌的控制台就行测试!!

1、基本用法:

(1)、首先我们new一个Promise,将Promise实例化

(2)、然后在实例化的promise可以传两个参数,一个是成功之后的resolve,一个是失败之后的reject

(3)、Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数

代码如下:

var promise = function(isReady){
 return new Promise(function(resolve, reject){
 // do somthing, maybe async
 if (isReady){
  return resolve('hello world');
 } else {
  return reject('failure');
 }
 });
}
//Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promise(true).then(function(value){
 // success,这里是resolve的回调函数
 console.log(value); //hello world
}, function(err){
 // failure,这里是reject的回调函数
 console.log(err)
})

上述代码是执行成功,返回hello world,如果想测试一下失败后的返回值,可以在promise(true).then...这里改为 promise(false).then...即可

2、链式操作

也许你会说,Promise只是简化层层回调的写法而已吧,其实不然,它的精髓是通过维护状态、传递状态的方式来使回调方式能够及时的调用,因此,相比于callback,它更灵活,更简单。下面我们来看看Promise的链式操作:

makePromise1()
.then(function(value){
 console.log(value);
 return makePromise2();
})
.then(function(value){
 console.log(value);
 return makePromise3();
})
.then(function(value){
 console.log(value);
});
function makePromise1(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务1');
  resolve('异步任务1传过来的值');
 }, 2000);
 });
 return p;  
}
function makePromise2(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务2');
  resolve('异步任务2传过来的值');
 }, 2000);
 });
 return p;  
}
function makePromise3(){
 var p = new Promise(function(resolve, reject){
 //异步操作
 setTimeout(function(){
  console.log('异步任务3');
  resolve('异步任务3传过来的值');
 }, 2000);
 });
 return p;  
}

上面的代码中,我们有三个异步操作,makePromise1,makePromise2,makePromise3。其中第二个和第三个依次执行,也就是上一个操作完成之后才可以进行。

输出的值为:

异步任务1
异步任务1传过来的值
异步任务2
异步任务2传过来的值
异步任务3
异步任务3传过来的值

3、Promise的catch方法

var promise = function(isReady){
 return new Promise(function(resolve, reject){
 // do somthing, maybe async
 if (isReady){
  return resolve('hello world');
 } else {
  return reject('failure');
 }
 });
}
promise(true)
.then(function(value){
 console.log('resolved');
 console.log(value);
 console.log(haha); //此处的haha未定义
})
.catch(function(error){
 console.log('rejected');
 console.log(error);
});

catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成 then(fn).catch(fn),相当于 then(fn).then(null, fn)

使用 catch 的写法比一般的写法更加清晰明确,其实可以类比成try/catch,这样,其中有报错的地方不会阻塞运行。比如定义了一个未定义haha,正常来说它上面的代码也不会运行,因为被这个报错阻塞了,有了catch,它上面的代码可以正常运行下去:

控制台打印出来的东西:

resolved
hello world
rejected
ReferenceError: haha is not defined(…)

4、promise.all方法

Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。

代码示例:

var p1 = new Promise(function (resolve) {
 setTimeout(function () {
 resolve("第一个promise");
 }, 3000);
});
var p2 = new Promise(function (resolve) {
 setTimeout(function () {
 resolve("第二个promise");
 }, 1000);
});
Promise.all([p1, p2]).then(function (result) {
 console.log(result); // ["第一个promise", "第二个promise"]
});

上面的代码中,all接收一个数组作为参数,p1,p2是并行执行的,等两个都执行完了,才会进入到then,all会把所有的结果放到一个数组中返回,所以我们打印出我们的结果为一个数组。

值得注意的是,虽然p2的执行顺序比p1快,但是all会按照参数里面的数组顺序来返回结果。all的使用场景类似于,玩游戏的时候,需要提前将游戏需要的资源提前准备好,才进行页面的初始化。

5、promise.race方法

race的中文意思为赛跑,也就是说,看谁跑的快,跑的快的就赢了。因此,promise.race也是传入一个数组,但是与promise.all不同的是,race只返回跑的快的值,也就是说result返回比较快执行的那个。

var p1 = new Promise(function (resolve) {
 setTimeout(function () {
 console.log(1);
 resolve("第一个promise");
 }, 3000);
});
var p2 = new Promise(function (resolve) {
 setTimeout(function () {
 console.log(2);
 resolve("第二个promise");
 }, 1000);
});
Promise.race([p1, p2]).then(function (result) {
 console.log(result); 
});
// 结果:
// 2
// 第二个promise
// 1

可以看到,传的值中,只有p2的返回了,但是p1没有停止,依然有执行。

race的应用场景为,比如我们可以设置为网路请求超时。写两个promise,如果在一定的时间内如果成功的那个我们没有执行到,我们就执行失败的那个,这里不再举例子,可以看看阮一峰的ES入门。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
防止文件缓存的js代码
Jan 10 Javascript
jquery中交替点击事件toggle方法的使用示例
Dec 08 Javascript
jQuery+HTML5加入购物车代码分享
Oct 29 Javascript
angular.js 路由及页面传参示例
Feb 24 Javascript
node.js实现微信JS-API封装接口的示例代码
Sep 06 Javascript
vue v-model动态生成详解
Jun 30 Javascript
使vue实现jQuery调用的两种方法
May 12 jQuery
VueJS 取得 URL 参数值的方法
Jul 19 Javascript
vue如何在用户要关闭当前网页时弹出提示的实现
May 31 Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
Jul 21 Javascript
详解JS深拷贝与浅拷贝
Aug 04 Javascript
Vue中 axios delete请求参数操作
Aug 25 Javascript
JS多文件上传的实例代码
Jan 11 #Javascript
微信小程序开发(一) 微信登录流程详解
Jan 11 #Javascript
Javascript中return的使用与闭包详解
Jan 11 #Javascript
jQuery对table表格进行增删改查
Dec 22 #Javascript
javascript基础知识讲解
Jan 11 #Javascript
bootstrap侧边栏圆点导航
Jan 11 #Javascript
微信小程序开发(二)图片上传+服务端接收详解
Jan 11 #Javascript
You might like
PHP编码转换
2012/11/05 PHP
destoon实现不同会员组公司名称显示不同的颜色的方法
2014/08/22 PHP
php天翼开放平台短信发送接口实现方法
2014/12/22 PHP
利用phpexcel对数据库数据的导入excel(excel筛选)、导出excel
2017/04/27 PHP
ASP.NET中基于JQUERY的高性能的TreeView补充
2011/02/23 Javascript
jQuery mobile 移动web(4)
2015/12/20 Javascript
javascript弹出带文字信息的提示框效果
2016/07/19 Javascript
Vue实现双向绑定的方法
2016/12/22 Javascript
JavaScript实现经典排序算法之插入排序
2016/12/28 Javascript
d3.js实现立体柱图的方法详解
2017/04/28 Javascript
Vue单文件组件的如何使用方式介绍
2017/07/28 Javascript
jQuery Raty星级评分插件使用方法实例分析
2019/11/25 jQuery
JS原形与原型链深入详解
2020/05/09 Javascript
vue-cli脚手架的.babelrc文件用法说明
2020/09/11 Javascript
javascript贪吃蛇游戏设计与实现
2020/09/17 Javascript
详解vue之自行实现派发与广播(dispatch与broadcast)
2021/01/19 Vue.js
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
web.py中调用文件夹内模板的方法
2014/08/26 Python
在 Python 应用中使用 MongoDB的方法
2017/01/05 Python
python pyheatmap包绘制热力图
2018/11/09 Python
python实现坦克大战游戏 附详细注释
2020/03/27 Python
关于Keras模型可视化教程及关键问题的解决
2020/01/24 Python
python实例化对象的具体方法
2020/06/17 Python
Python生成器传参数及返回值原理解析
2020/07/22 Python
python爬虫快速响应服务器的做法
2020/11/24 Python
python自动化发送邮件实例讲解
2021/01/04 Python
html5仿支付宝密码框的实现代码
2017/09/06 HTML / CSS
canvas中普通动效与粒子动效的实现代码示例
2019/01/03 HTML / CSS
Myprotein葡萄牙官方网站:英国优质运动营养品牌
2016/09/12 全球购物
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
美国领先的家庭智能音响系统品牌:Sonos
2018/07/20 全球购物
求职信的要素有哪些呢
2013/12/26 职场文书
小学教师培训感言
2014/02/11 职场文书
2014小学一年级班主任工作总结
2014/12/05 职场文书
重阳节简报
2015/07/20 职场文书
快消品行业营销模式与盈利模式分享
2019/09/27 职场文书