Promi知识总结
本⽂⽬录:
1.什么是回调函数?回调函数有什么缺点
e是什么,可以⼿写实现⼀下吗
3.⼿写简单版的Promi
,catch,finally
5.⼿写
6.⼿写
e⾥都是微任务吗
wait和promi的区别与联系
e中⽤了什么设计模式
1.什么是回调函数?回调函数有什么缺点
回调函数是⼀段可执⾏的代码段,它作为⼀个参数传递给其他的代码,其作⽤是在需要的时候⽅便调⽤这段(回调函数)代码。
在JavaScript中函数也是对象的⼀种,同样对象可以作为参数传递给函数,因此函数也可以作为参数传递给另外⼀个函数,这个作为参数的函数
就是回调函数。
constbtnAdd=mentById('btnAdd');
ntListener('click',functionclickCallback(e){
//dosomethinguless
});
在本例中,我们等待id为btnAdd的元素中的click事件,如果它被单击,则执⾏clickCallback函数。回调函数向某些数据或事件添加⼀些功能。
回调函数有⼀个致命的弱点,就是容易写出回调地狱(Callbackhell)。假设多个事件存在依赖性:
tTimeout(()=>{
(1)
tTimeout(()=>{
(2)
tTimeout(()=>{
(3)
},3000)
},2000)
},1000)
这就是典型的回调地狱,以上代码看起来不利于阅读和维护,事件⼀旦多起来就更是乱糟糟,所以在es6中提出了Promi和async/await来解决
回调地狱的问题。当然,回调函数还存在着别的⼏个缺点,⽐如不能使⽤trycatch捕获错误,不能直接return。
e是什么,可以⼿写实现⼀下吗
Promi,翻译过来是承诺,承诺它过⼀段时间会给你⼀个结果。从编程讲Promi是异步编程的⼀种解决⽅案。下⾯是Promi在MDN的相关
说明:
Promi对象是⼀个代理对象(代理⼀个值),被代理的值在Promi对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相
应的处理⽅法(handlers)。这让异步⽅法可以像同步⽅法那样返回值,但并不是⽴即返回最终执⾏结果,⽽是⼀个能代表未来出现的结果的
promi对象。
⼀个Promi有以下⼏种状态:
pending:初始状态,既不是成功,也不是失败状态。
fulfilled:意味着操作成功完成。
rejected:意味着操作失败。
这个承诺⼀旦从等待状态变成为其他状态就永远不能更改状态了,也就是说⼀旦状态变为fulfilled/rejected后,就不能再次改变。可能光看概念
⼤家不理解Promi,我们举个简单的栗⼦;
假如我有个⼥朋友,下周⼀是她⽣⽇,我答应她⽣⽇给她⼀个惊喜,那么从现在开始这个承诺就进⼊等待状态,等待下周⼀的到来,然后状态改
变。如果下周⼀我如约给了⼥朋友惊喜,那么这个承诺的状态就会由pending切换为fulfilled,表⽰承诺成功兑现,⼀旦是这个结果了,就不会再
有其他结果,即状态不会在发⽣改变;反之如果当天我因为⼯作太忙加班,把这事给忘了,说好的惊喜没有兑现,状态就会由pending切换为
rejected,时间不可倒流,所以状态也不能再发⽣变化。
上⼀条我们说过Promi可以解决回调地狱的问题,没错,pending状态的Promi对象会触发fulfilled/rejected状态,⼀旦状态改
变,Promi对象的then⽅法就会被调⽤;否则就会触发catch。我们将上⼀条回调地狱的代码改写⼀下:
newPromi((resolve,reject)=>{
tTimeout(()=>{
(1)
resolve()
},1000)
}).then((res)=>{
tTimeout(()=>{
(2)
},2000)
}).then((res)=>{
tTimeout(()=>{
(3)
},3000)
}).catch((err)=>{
(err)
})
其实Promi也是存在⼀些缺点的,⽐如⽆法取消Promi,错误需要通过回调函数捕获。
3.⼿写简单版的Promi
promi⼿写实现,⾯试够⽤版:
functionmyPromi(executor){
var_this=this;
illed=[];//成功的回调
cted=[];//失败的回调
="PENDING";//状态
=undefined;//成功结果
=undefined;//失败原因
functionresolve(value){
if(_==="PENDING"){
_="FULFILLED";
_=value;
_h((fn)=>fn(value));
}
}
functionreject(reason){
if(_==="PENDING"){
_="REJECTED";
_=reason;
_h((fn)=>fn(reason));
}
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
//定义链式调⽤的then⽅法
=function(onFullfilled,onRejected){
if(==="FULFILLED"){
typeofonFulfilled==="function"&&onFulfilled();
}
if(==="REJECTED"){
typeofonRejected==="function"&&onRejected();
}
if(==="PENDING"){
typeofonFulfilled==="function"&&
(onFulfilled);
typeofonRejected==="function"&&(onRejected);
}
};
varmyP=newmyPromi((resolve,reject)=>{
("执⾏");
tTimeout(()=>{
reject(3);
},1000);
});
(
(res)=>{
(res);
},
(err)=>{
(err);
}
);
,catch,finally
then⽅法的第⼀个参数是resolved状态对应的回调函数,第⼆个参数(可选)是rejected状态对应的回调函数,then⽅法返回的是⼀个新的
Promi实例.(注意,不是原来那个Promi实例),因此可以采⽤链式写法,即then⽅法后⾯再调⽤另⼀个then⽅法.
getJSON("/").then(function(json){
;
}).then(function(post){
//...
});
()⽅法是`.then(null,rejection)或.then(undefined,rejection)的别名,⽤于指定发⽣错误时的回调函数.
getJSON('/').then(function(posts){
//...
}).catch(function(error){
//处理getJSON和前⼀个回调函数运⾏时发⽣的错误
('发⽣错误!',error);
});
上⾯代码中,getJSON()⽅法返回⼀个Promi对象,如果该对象状态变为resolved,则会调⽤then()⽅法指定的回调函数;如果异步操作抛出
错误,状态就会变为rejected,就会调⽤catch()⽅法指定的回调函数,处理这个错误。另外,then()⽅法指定的回调函数,如果运⾏中抛出错
误,也会被catch()⽅法捕获。
finally()⽅法⽤于指定不管Promi对象最后状态如何,都会执⾏的操作。该⽅法是ES2018引⼊标准的。
promi
.then(result=>{···})
.catch(error=>{···})
.finally(()=>{···});
上⾯代码中,不管promi最后的状态,在执⾏完then或catch指定的回调函数以后,都会执⾏finally⽅法指定的回调函数。
finally⽅法的回调函数不接受任何参数,这意味着没有办法知道,前⾯的Promi状态到底是fulfilled还是rejected。这表明,finally⽅法⾥⾯
的操作,应该是与状态⽆关的,不依赖于Promi的执⾏结果。
5.⼿写
⽅法:当参数中的promi有⼀个失败了就直接返回失败的结果,返回第⼀个失败的结果,都成功返回所有的参数结果
思路:
返回⼀个新的promi,并遍历调⽤传⼊的promi组成的数组参数,利⽤e()⽅法获取成功执⾏的所有promi的数量和数组参
数的长度进⾏⽐对,如果长度⼩于参数,则代表有失败的结果,否则就是全部成功。
functionpromiAll(promis){
//返回⼀个promi实例
returnnewPromi((resolve,reject)=>{
//做⼀个判断参数是否是数组
if(!y(promis)){
returnreject(newTypeError('argumentsmustbeArray'))
}
letcount=0,
newValues=newArray()//接收新的结果参数建⽴⼀个伪数组
for(leti=0;i<;i++){
//运⽤promi特性只会有⼀个状态
e(promis[i])
.then(res=>{
count++
newValues[i]=res//把每次返回成功的数据添加到数组中
if(count===){//数据接收完成
resolve(newValues)
}
},rej=>reject(rej))
}
})
}
成功的时候返回的是⼀个结果数组,⽽失败的时候则返回最先被reject失败状态的值。,需要注意的是,获得的成功结果的数组⾥⾯的
数据顺序和接收到的数组顺序是⼀致的。
6.⼿写
就是赛跑的意思,意思就是说,([p1,p2,p3])⾥⾯哪个结果获得的快,就返回那个结果,不管结果本⾝是成功状态还
是失败状态。
functionpromiRace(arrays){
if(!y(arrays))
return'notArray'
returnnewPromi((resolve,reject)=>{
for(vari=0;i<;i++){
e(arrays[i]).then((value)=>{
resolve(value)
},(err)=>{reject(err)})
}
})
}
e⾥都是微任务吗
Promi中只有涉及到状态变更后才需要被执⾏的回调才算是微任务,⽐如说then、catch、finally,其他所有的代码执⾏都是宏任务(同步
执⾏)。
wait和promi的区别与联系
asyncawait和promi都是异步编程解决⽅案。
Promi的写法只是回调函数的改进,使⽤then⽅法,只是让异步任务的两段执⾏更清楚⽽已。Promi的最⼤问题是代码冗余,请求任务多
时,⼀堆的then,也使得原来的语义变得很不清楚。
async搭配await是ES7提出的,它的实现是基于Promi,通过同步⽅式的写法,使得代码更容易阅读。
async/await的优势在于处理then的调⽤链,能够更清晰准确的写出代码,并且也能优雅地解决回调地狱问题。当然也存在⼀些缺点,因为
await将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使⽤了await会导致性能上的降低。
e中⽤了什么设计模式
观察者模式在软件设计中是⼀个对象,维护⼀个依赖列表,当任何状态发⽣改变⾃动通知它们。
发布-订阅模式是⼀种消息传递模式,消息的发布者(Publishers)⼀般将消息发布到特定消息中⼼,订阅者(Subscriber)可以按照⾃⼰的需求
从消息中⼼订阅信息,跟消息队列挺类似的。
观察者设计模式的代码实现
//观察者设计模式
classObrver{
constructor(){
erList=[];
}
subscribe(obrver){
(obrver)
}
notifyAll(value){
h(obrve=>obrve(value))
}
}
发布-订阅设计模式的代码实现
//发布订阅
classEventEmitter{
constructor(){
hannel={};//消息中⼼
}
//subscribe
on(event,callback){
hannel[event]?hannel[event].push(callback):hannel[event]=[callback]
}
//publish
emit(event,...args){
hannel[event]&&hannel[event].forEach(callback=>callback(...args))
}
//removeevent
remove(event){
if(hannel[event]){
hannel[event]
}
}
//onceevent
once(event,callback){
(event,(...args)=>{
callback(...args);
(event)
})
}
}
从代码中也能看出他们的区别,观察者模式不对事件进⾏分类,当有事件时,将通知所有观察者。发布-订阅设计模式对事件进⾏了分类,触发不
同的事件,将通知不同的观察者。所以可以认为后者就是前者的⼀个升级版,对通知事件做了更细粒度的划分。
发布-订阅和观察者在异步中的应⽤
观察者模式
constobrver=newObrver();
ibe(value=>{
("第⼀个观察者,接收到的值为:");
(value)
});
ibe(value=>{
("第⼆个观察者,接收到的值为");
(value)
});
le("",(err,data)=>{
All(ng())
});
发布-订阅模式
//发布-订阅
constevent=newEventEmitter();
("err",);
("data",data=>{
//dosomething
(data)
});
le("",(err,data)=>{
if(err)("err",err);
("data",ng())
});
两种设计模式在异步编程中,都是通过注册全局观察者或全局事件,然后在异步环境⾥通知所有观察者或触发特定事件来实现异步编程。
劣势也很明显,⽐如全局观察者/事件过多难以维护,事件名命冲突等等,因此Promi便诞⽣了,Promi在⼀定程度上继承了观察者和发布-订
阅设计模式的思想。
本文发布于:2022-12-31 05:39:55,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/64104.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |