美团经典面试题解析——如何手写一个Promi

更新时间:2023-07-17 13:59:06 阅读: 评论:0

美团经典⾯试题解析——如何⼿写⼀个Promi 前⾔
⼿写实现Promi是⼀道经典的前端⾯试题。⽐如在美团,Promi⼏乎就是必考题,在其它互联⽹⼀线⼤⼚也是⾼频题⽬。Promi的实现相对⽐较复杂,考虑的逻辑也⽐较多,下⾯带着⼤家逐⼀分析,找到其关键点、以及如何⼿写⼀个Promi。(本⽂实现遵循 )
1. Promi 基本结构
我们知道实例化Promi对象时传⼊⼀个函数作为执⾏器,有两个参数(resolve和reject)分别将结果变为成功态和失败态。据此我们可以写出基本结构:
function Promi(excutor){
let lf = this;
lf.status = 'pending';    // 状态等待 => 成功或失败
lf.value = null;          // 成功结果
function resolve(value){
};
function reject(reason){
};
}
矫枉过正的读音2. then⽅法
每⼀个Promi实例都有⼀个then⽅法,它⽤来处理异步返回的结果,它是定义在原型上的⽅法。
// ⼀个成功⼀个失败
Promi.prototype.then = function(onFulfilled, onRejected){
}
当我们⾃⼰实例化⼀个Promi时,其执⾏器函数(executor)会⽴即执⾏,这是⼀定的:
let demo = new Promi((resolve, reject)=>{
console.log("在座的各位彭于晏,⼤家好");
})
因此,当实例化Promi时,构造函数中就要马上调⽤传⼊的excutor函数执⾏,为了防⽌出错,加⼊try,catch:
// 此段代码放在Promi⽅法⾥
try {
excutor(resolve, reject);
} catch(err) {
reject(err)梦到火灾
}
3. 状态管理
已经是成功态或是失败态不可再更新状态,Promi 规范中规定:当Promi对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态。
餐厅管理规章制度
因此我们在更新状态时要判断,如果当前状态是pending(等待态)才可更新。
function resolve(value){
if (lf.status === 'pending') {
lf.value = value; //保存成功结果
lf.status = 'fulfilled';
}
}
function reject(reason){
if (lf.status === 'pending') {
lf.status = 'rejected';
}
}
以上可以看到:八级伤残鉴定标准
1. 在resolve和reject函数中分别加⼊了判断
2. 只有当前状态是pending才可进⾏操作
3. 将成功的结果和失败的原因都保存到对应的属性上。之后将state属性置为更新后的状态
4. then⽅法完善
当Promi的状态发⽣了改变,不论是成功或是失败都会调⽤then⽅法。所以,then⽅法的实现也很简单,根据state状态来调⽤不同的回调函数即可。
Promi.prototype.then = function(onFulfilled, onRejected){
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : function (data) { resolve(data) }
onRejected = typeof onRejected === 'function' ?
onRejected : function (err) { throw err }
}
代码写到这⾥似乎基本功能都实现了,可是还有⼀个很⼤的问题:⽬前此Promi还不⽀持异步代码,如果Promi中封装的是异步操作,then⽅法⽆能为⼒,例:
let demo = new Promi((resolve, reject)=>{
console.log("在座的各位彭于晏⼤家好");
tTimeout(()=>{
resolve(1);
}, 500)
})
// 没有打印
demo.then(data => console.log(data));
第⼀步是正常打印的,但是 tTimeout ⾥⾯的代码不会执⾏,最后⼀⾏也不会打印 “1”。
问题所在:原因是 tTimeout 函数使得 resolve 是异步执⾏的,有延迟,当调⽤then⽅法的时候,此时此刻的状态还是等待态(pending),因此then⽅法即没有调⽤ onFulfilled 也没有调⽤ onRejected。
5. 发布订阅模式登场
这个问题如何解决?我们可以参照发布订阅模式,在执⾏ then ⽅法时如果还在等待态(pending),就把回调函数临时寄存到⼀个数组⾥,当状态发⽣改变时依次从数组中取出执⾏就好,是不是很Nice!
清楚这个思路我们开始实现它,⾸先在类上新增两个Array类型的数组,⽤于存放回调函数:
function Promi(excutor){
// 其它代码略
}
在then⽅法⾥添加进去:
Promi.prototype.then = function(onFulfilled, onRejected){
// 其它代码略
let lf = this;
if(lf.status === "pending"){
亲子农场
}
}
在resolve() 与reject() ⾥逐⼀遍历:
function resolve(value){
if (lf.status === 'pending') {
// 其它代码略
}
}
function reject(reason){
基督教舞蹈网
if (lf.status === 'pending') {
// 其它代码略
}
手上长冻疮怎么办}
到这⼀步,异步也搞定了!再是如何实现链式调⽤。
6. 经典的链式调⽤实现
then⽅法接收的两个函数中,可以通过return把值传给下⼀个步,也可以返回⼀个新的Promi把值传给下⼀步,then⽅法执⾏的时候有个特点:
为了保证链式调⽤,上⼀次then中不管你是成功还是失败都会把参数作为下⼀个then中成功时回调的参数
话不多说,开⼲(只需要再new⼀个Promi即可):
Promi.prototype.then = function(onFulfilled, onRejected){
onFulfilled = typeof onFulfilled === 'function' ?
onFulfilled : function (data) { resolve(data) }
onRejected = typeof onRejected === 'function' ?
onRejected : function (err) { throw err }
let lf = this;
if(lf.status === "fulfilled"){
return new Promi((resolve, reject) => {
try{
let x = onFulfilled(lf.value);
x instanceof Promi ? x.then(resolve, reject) : resolve(x);
} catch (err){
reject(err)
}
})
}
if(lf.status === "rejected"){
return new Promi((resolve, reject) => {
try{
let x = ason);
x instanceof Promi ? x.then(resolve, reject) : resolve(x);
} catch (err){
reject(err)
}
})
}
if(lf.status === "pending"){
return new Promi((resolve, reject) => {
let x = onFulfilled(lf.value);
x instanceof Promi ? x.then(resolve, reject) : resolve(x);
梁启超图片})
let x = ason);
x instanceof Promi ? x.then(resolve, reject) : resolve(x);
})
})
}
}
}
7. 最后的catch⽅法
其实catch⽅法就是then⽅法的简写
Promi.prototype.catch = function(fn){
return this.then(null, fn);
}
现在,⼀个完整的Promi就实现了,⼤家可以去试试。有啥不对的可以在评论区指出,感谢。
考虑到⼀些新⼿基础可能差点,本篇⽂章可以说讲解的⾮常⾮常详细了,拆分了多个⼩步骤,⼀步⼀步来。相信⼤家跟着思路⾛都是能搞定的。排版啥的也都尽量搞得好看些,提⾼各位客官的⽤户体验。
如果对⼤家有帮助,欢迎点赞、评论和转发,再次感谢⼤家的⽀持,我会持续更新。

本文发布于:2023-07-17 13:59:06,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1101435.html

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

标签:状态   实现   函数   结果
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图