promi什么意思

更新时间:2022-12-27 03:37:05 阅读: 评论:0


2022年12月27日发(作者:container是什么意思)

ES6Promi⽤法讲解

所谓Promi,简单说就是⼀个容器,⾥⾯保存着某个未来才会结束的事件(通常是⼀个异步操作)的结果。

ES6规定,Promi对象是⼀个构造函数,⽤来⽣成Promi实例。

下⾯代码创造了⼀个Promi实例。

constpromi=newPromi(function(resolve,reject){

//...somecode

if(/*异步操作成功*/){

resolve(value);

}el{

reject(error);

}

});

Promi构造函数接受⼀个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不⽤⾃⼰

部署。

resolve函数的作⽤是,将Promi对象的状态从“未完成”变为“成功”(即从pending变为resolved),在异步操作成功时调⽤,并将异步操

作的结果,作为参数传递出去;reject函数的作⽤是,将Promi对象的状态从“未完成”变为“失败”(即从pending变为rejected),在异步

操作失败时调⽤,并将异步操作报出的错误,作为参数传递出去。

Promi实例⽣成以后,可以⽤then⽅法分别指定resolved状态和rejected状态的回调函数。

(function(value){

//success

},function(error){

//failure

});

then⽅法可以接受两个回调函数作为参数。第⼀个回调函数是Promi对象的状态变为resolved时调⽤,第⼆个回调函数是Promi对象的状

态变为rejected时调⽤。其中,第⼆个函数是可选的,不⼀定要提供。这两个函数都接受Promi对象传出的值作为参数。

下⾯是⼀个Promi对象的简单例⼦。

functiontimeout(ms){

returnnewPromi((resolve,reject)=>{

tTimeout(resolve,ms,'done');

});

}

timeout(100).then((value)=>{

(value);

});

上⾯代码中,timeout⽅法返回⼀个Promi实例,表⽰⼀段时间以后才会发⽣的结果。过了指定的时间(ms参数)以后,Promi实例的状

态变为resolved,就会触发then⽅法绑定的回调函数。

Promi新建后就会⽴即执⾏。

letpromi=newPromi(function(resolve,reject){

('Promi');

resolve();

});

(function(){

('resolved.');

});

('Hi!');

//Promi

//Hi!

//resolved

上⾯代码中,Promi新建后⽴即执⾏,所以⾸先输出的是Promi。然后,then⽅法指定的回调函数,将在当前脚本所有同步任务执⾏完

才会执⾏,所以resolved最后输出。

下⾯是异步加载图⽚的例⼦。

functionloadImageAsync(url){

returnnewPromi(function(resolve,reject){

constimage=newImage();

=function(){

resolve(image);

};

r=function(){

reject(newError('Couldnotloadimageat'+url));

};

=url;

});

}

上⾯代码中,使⽤Promi包装了⼀个图⽚加载的异步操作。如果加载成功,就调⽤resolve⽅法,否则就调⽤reject⽅法。

Promi是⼀个构造函数,⾃⼰⾝上有all、reject、resolve这⼏个眼熟的⽅法,原型上有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,报出“图⽚请求超时”的信息。运⾏结果如下:

本文发布于:2022-12-27 03:37:05,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/37856.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:nice的意思
下一篇:try是什么意思
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图