ES6---newPromi()使⽤⽅法
2015年6⽉份,ES2015正式发布(也就是ES6,ES6是它的乳名),其中Promi被列为正式规范。作为ES6中最重要的特性之⼀,我
们有必要掌握并理解透彻。本⽂将由浅到深,讲解Promi的基本概念与使⽤⽅法。
ES6Promi先拉出来遛遛
复杂的概念先不讲,我们先简单粗暴地把Promi⽤⼀下,有个直观感受。那么第⼀个问题来了,Promi是什么玩意呢?是⼀个类?对
象?数组?函数?
别猜了,直接打印出来看看吧,(Promi),就这么简单粗暴。
这么⼀看就明⽩了,Promi是⼀个构造函数,⾃⼰⾝上有all、reject、resolve这⼏个眼熟的⽅法,原型上有then、catch等同样很眼熟
的⽅法。这么说⽤Prominew出来的对象肯定就有then、catch⽅法喽,没错。
那就new⼀个玩玩吧。
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
('执⾏完成');
resolve('随便什么数据');
},2000);
});
Promi的构造函数接收⼀个参数,是函数,并且传⼊两个参数:resolve,reject,分别表⽰异步操作执⾏成功后的回调函数和异步操作
执⾏失败后的回调函数。其实这⾥⽤“成功”和“失败”来描述并不准确,按照标准来讲,resolve是将Promi的状态置为
fullfiled,reject是将Promi的状态置为rejected。不过在我们开始阶段可以先这么理解,后⾯再细究概念。
在上⾯的代码中,我们执⾏了⼀个异步操作,也就是tTimeout,2秒后,输出“执⾏完成”,并且调⽤resolve⽅法。
运⾏代码,会在2秒后输出“执⾏完成”。注意!我只是new了⼀个对象,并没有调⽤它,我们传进去的函数就已经执⾏了,这是需要注意
的⼀个细节。所以我们⽤Promi的时候⼀般是包在⼀个函数中,在需要的时候去运⾏这个函数,如:
functionrunAsync(){
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
('执⾏完成');
resolve('随便什么数据');
},2000);
});
returnp;
}
runAsync()
这时候你应该有两个疑问:1.包装这么⼀个函数有⽑线⽤?e('随便什么数据');这是⼲⽑的?
我们继续来讲。在我们包装好的函数最后,会return出Promi对象,也就是说,执⾏这个函数我们得到了⼀个Promi对象。还记得
Promi对象上有then、catch⽅法吧?这就是强⼤之处了,看下⾯的代码:
runAsync().then(function(data){
(data);
//后⾯可以⽤传过来的数据做些其他操作
//......
});
在runAsync()的返回上直接调⽤then⽅法,then接收⼀个参数,是函数,并且会拿到我们在runAsync中调⽤resolve时传的的参数。运⾏
这段代码,会在2秒后输出“执⾏完成”,紧接着输出“随便什么数据”。
这时候你应该有所领悟了,原来then⾥⾯的函数就跟我们平时的回调函数⼀个意思,能够在runAsync这个异步任务执⾏完成之后被执⾏。
这就是Promi的作⽤了,简单来讲,就是能把原来的回调写法分离出来,在异步操作执⾏完后,⽤链式调⽤的⽅式执⾏回调函数。
你可能会不屑⼀顾,那么⽜逼轰轰的Promi就这点能耐?我把回调函数封装⼀下,给runAsync传进去不也⼀样吗,就像这样:
functionrunAsync(callback){
tTimeout(function(){
('执⾏完成');
callback('随便什么数据');
},2000);
}
runAsync(function(data){
(data);
});
效果也是⼀样的,还费劲⽤Promi⼲嘛。那么问题来了,有多层回调该怎么办?如果callback也是⼀个异步操作,⽽且执⾏完后也需要有
相应的回调函数,该怎么办呢?总不能再定义⼀个callback2,然后给callback传进去吧。⽽Promi的优势在于,可以在then⽅法中继续
写Promi对象并返回,然后继续调⽤then来进⾏回调操作。
链式操作的⽤法
所以,从表⾯上看,Promi只是能够简化层层回调的写法,⽽实质上,Promi的精髓是“状态”,⽤维护状态、传递状态的⽅式来使得
回调函数能够及时调⽤,它⽐传递callback函数要简单、灵活的多。所以使⽤Promi的正确场景是这样的:
runAsync1()
.then(function(data){
(data);
returnrunAsync2();
})
.then(function(data){
(data);
returnrunAsync3();
})
.then(function(data){
(data);
});
这样能够按顺序,每隔两秒输出每个异步回调中的内容,在runAsync2中传给resolve的数据,能在接下来的then⽅法中拿到。运⾏结果如
下:
猜猜runAsync1、runAsync2、runAsync3这三个函数都是如何定义的?没错,就是下⾯这样(代码较长请⾃⾏展开):
functionrunAsync1(){
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
('异步任务1执⾏完成');
resolve('随便什么数据1');
},1000);
});
returnp;
}
functionrunAsync2(){
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
('异步任务2执⾏完成');
resolve('随便什么数据2');
},2000);
});
returnp;
}
functionrunAsync3(){
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
('异步任务3执⾏完成');
resolve('随便什么数据3');
},2000);
});
returnp;
}
在then⽅法中,你也可以直接return数据⽽不是Promi对象,在后⾯的then中就可以接收到数据了,⽐如我们把上⾯的代码修改成这
样:
runAsync1()
.then(function(data){
(data);
returnrunAsync2();
})
.then(function(data){
(data);
return'直接返回数据';//这⾥直接返回数据
})
.then(function(data){
(data);
});
那么输出就变成了这样:
reject的⽤法
到这⾥,你应该对“Promi是什么玩意”有了最基本的了解。那么我们接着来看看ES6的Promi还有哪些功能。我们光⽤了resolve,
还没⽤reject呢,它是做什么的呢?事实上,我们前⾯的例⼦都是只有“执⾏成功”的回调,还没有“失败”的情况,reject的作⽤就是把
Promi的状态置为rejected,这样我们在then中就能捕捉到,然后执⾏“失败”情况的回调。看下⾯的代码。
functiongetNumber(){
varp=newPromi(function(resolve,reject){
//做⼀些异步操作
tTimeout(function(){
varnum=(()*10);//⽣成1-10的随机数
if(num<=5){
resolve(num);
}
el{
reject('数字太⼤了');
}
},2000);
});
returnp;
}
getNumber()
.then(
function(data){
('resolved');
(data);
},
function(reason,data){
('rejected');
(reason);
}
);
getNumber函数⽤来异步获取⼀个数字,2秒后执⾏完成,如果数字⼩于等于5,我们认为是“成功”了,调⽤resolve修改Promi的状
态。否则我们认为是“失败”了,调⽤reject并传递⼀个参数,作为失败的原因。
运⾏getNumber并且在then中传了两个参数,then⽅法可以接受两个参数,第⼀个对应resolve的回调,第⼆个对应reject的回调。所以我
们能够分别拿到他们传过来的数据。多次运⾏这段代码,你会随机得到下⾯两种结果:
或者
catch的⽤法
我们知道Promi对象除了then⽅法,还有⼀个catch⽅法,它是做什么⽤的呢?其实它和then的第⼆个参数⼀样,⽤来指定reject的回
调,⽤法是这样:
getNumber()
.then(function(data){
('resolved');
(data);
})
.catch(function(reason){
('rejected');
(reason);
});
效果和写在then的第⼆个参数⾥⾯⼀样。不过它还有另外⼀个作⽤:在执⾏resolve的回调(也就是上⾯then中的第⼀个参数)时,如果抛
出异常了(代码出错了),那么并不会报错卡死js,⽽是会进到这个catch⽅法中。请看下⾯的代码:
getNumber()
.then(function(data){
('resolved');
(data);
(somedata);//此处的somedata未定义
})
.catch(function(reason){
('rejected');
(reason);
});
在resolve的回调中,我们(somedata);⽽somedata这个变量是没有被定义的。如果我们不⽤Promi,代码运⾏到这⾥就直
接在控制台报错了,不往下运⾏了。但是在这⾥,会得到这样的结果:
也就是说进到catch⽅法⾥⾯去了,⽽且把错误原因传到了reason参数中。即便是有错误的代码也不会报错了,这与我们的try/catch语句
有相同的功能。
all的⽤法
Promi的all⽅法提供了并⾏执⾏异步操作的能⼒,并且在所有异步操作执⾏完后才执⾏回调。我们仍旧使⽤上⾯定义好的runAsync1、
runAsync2、runAsync3这三个函数,看下⾯的例⼦:
Promi
.all([runAsync1(),runAsync2(),runAsync3()])
.then(function(results){
(results);
});
⽤来执⾏,all接收⼀个数组参数,⾥⾯的值最终都算返回Promi对象。这样,三个异步操作的并⾏执⾏的,等到它们都执⾏
完后才会进到then⾥⾯。那么,三个异步操作返回的数据哪⾥去了呢?都在then⾥⾯呢,all会把所有异步操作的结果放进⼀个数组中传给
then,就是上⾯的results。所以上⾯代码的输出结果就是:
有了all,你就可以并⾏执⾏多个异步操作,并且在⼀个回调中处理所有的返回数据,是不是很酷?有⼀个场景是很适合⽤这个的,⼀些游戏
类的素材⽐较多的应⽤,打开⽹页时,预先加载需要⽤到的各种资源如图⽚、flash以及各种静态⽂件。所有的都加载完后,我们再进⾏页
⾯的初始化。
race的⽤法
all⽅法的效果实际上是「谁跑的慢,以谁为准执⾏回调」,那么相对的就有另⼀个⽅法「谁跑的快,以谁为准执⾏回调」,这就是race⽅
法,这个词本来就是赛跑的意思。race的⽤法与all⼀样,我们把上⾯runAsync1的延时改为1秒来看⼀下:
Promi
.race([runAsync1(),runAsync2(),runAsync3()])
.then(function(results){
(results);
});
这三个异步操作同样是并⾏执⾏的。结果你应该可以猜到,1秒后runAsync1已经执⾏完了,此时then⾥⾯的就执⾏了。结果是这样的:
你猜对了吗?不完全,是吧。在then⾥⾯的回调开始执⾏时,runAsync2()和runAsync3()并没有停⽌,仍旧再执⾏。于是再过1秒后,输
出了他们结束的标志。
这个race有什么⽤呢?使⽤场景还是很多的,⽐如我们可以⽤race给某个异步请求设置超时时间,并且在超时后执⾏相应的操作,代码如
下:
//请求某个图⽚资源
functionrequestImg(){
varp=newPromi(function(resolve,reject){
varimg=newImage();
=function(){
resolve(img);
}
='xxxxxx';
});
returnp;
}
//延时函数,⽤于给请求计时
functiontimeout(){
varp=newPromi(function(resolve,reject){
tTimeout(function(){
reject('图⽚请求超时');
},5000);
});
returnp;
}
Promi
.race([requestImg(),timeout()])
.then(function(results){
(results);
})
.catch(function(reason){
(reason);
});
requestImg函数会异步请求⼀张图⽚,我把地址写为"xxxxxx",所以肯定是⽆法成功请求到的。timeout函数是⼀个延时5秒的异步操作。
我们把这两个返回Promi对象的函数放进race,于是他俩就会赛跑,如果5秒之内图⽚请求成功了,那么遍进⼊then⽅法,执⾏正常的流
程。如果5秒钟图⽚还未成功返回,那么timeout就跑赢了,则进⼊catch,报出“图⽚请求超时”的信息。运⾏结果如下:
总结
ES6Promi的内容就这些吗?是的,能⽤到的基本就这些。
我怎么还见过done、finally、success、fail等,这些是啥?这些并不在Promi标准中,⽽是我们⾃⼰实现的语法糖。
本⽂中所有异步操作均以tTimeout为例⼦,之所以不使⽤ajax是为了避免引起混淆,因为谈起ajax,很多⼈的第⼀反应就是jquery的
ajax,⽽jquery⼜有⾃⼰的Promi实现。如果你理解了原理,就知道使⽤tTimeout和使⽤ajax是⼀样的意思。说起jquery,我不得不
吐槽⼀句,jquery的Promi实现太过垃圾,各种语法糖把⼈都搞蒙了,我认为Promi之所以没有全⾯普及和jquery有很⼤的关系。后⾯
我们会细讲jquery。
本文发布于:2022-11-24 16:45:14,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/13039.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |