携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
如今前端面试中,除了问基础知识之外,经常还会问一些开放问题,来看开发者解决问题的思路,以及逻辑。
比如面试经常问的一个问题就是:如果让你手写一个promsie,你会怎么做?
像这种题目,面试官并不是真的想让你手写一个框架,而是看对promise的了解,思维方式
今天就简单的拆分一下手写promise的几个阶段
阶段1:
promsie大家肯定都用过,基本的用法也都知道。
new Promise((resolve, reject) => {
resolve(1)
}).then(res => {
console.log(res)
})
所以我们可以对promise进行一个简单的分析,至少可以得出三个结论
1. Promise是一个类
2. promise接收一个参数,参数是函数类型,且这个参数又接收两个函数参数,resolve, reject
3. promsie有一个then方法,一个catch方法
针对这三个结论,我们其实就可以开始写我们的第一个版本。
class MyPromise {
constructor(fn) {
this.status = "pending";
this.resolve_value = "";
this.reject_value = "";
this.resolve_fn = (val) => {
if (this.status === "pending") {
this.status = "success";
this.resolve_value = val;
}
};
this.reject_fn = (val) => {
if (this.status === "pending") {
this.status = "fail";
this.reject_value = val;
}
};
fn(this.resolve_fn, this.reject_fn);
}
then(reslove_then) {
if (this.status === "success") {
reslove_then(this.resolve_value);
}
}
catch(reject_catch) {
if (this.status === "fail") {
reject_catch(his.reject_value);
}
}
}
new MyPromise((resolve, reject) => {
resolve(1);
}).then((res) => {
console.log(res);
});
代码比较简单,都是基于之前的三个分析的代码。
版本2:
实现了基础版本,我们很容易就想到,promise是可以链式调用的,比如下面这样
new Promise((resolve, reject) => {
resolve(1);
}).then((res) => {
console.log(res);
return 2
}).then(res => {
console.log(res)
});
那么如何实现呢?
我们把then函数中的返回变成一个新的Promise对象就可以了。
then(reslove_then) {
return new MyPromise((reslove, reject) => {
if (this.status === "success") {
const okResult = reslove_then(this.resolve_value);
reslove(okResult);
}
})
}
new MyPromise((resolve, reject) => {
resolve(1);
}).then((res) => {
console.log(res);
return 2
}).then(res => {
console.log(res)
});
我们先来理一下逻辑(便于后续理解异步)
- 创建了一个Promise类,并把相应的参数传进去
- 执行resolve把值保存到resolve_value中
- 调用类的then方法,并传入一个函数reslove_then
- 执行函数并把resolve_value中的值传给reslove_then
版本3:
最后我们再来实现promise的异步功能,也是最主要的一个功能。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
}).then((res) => {
console.log(res);
});
异步的难点在于,第2步是异步的,所以在第4步中执行reslove_then的时候,resolve_value还没有被赋值,而且status还是pending状态。
那怎么解决呢?
我们可以先定义一个变量,把函数先存起来,等resolve执行完之后再执行。
// 1.先定义一个asynResolveList用来存异步resolve方法
this.asynResolveList = [];
// 2.然后在then方法中添加对pending的判断
if (this.status === "pending") {
this.asynResolveList.push(() => {
const okResult = reslove_then(this.resolve_value);
reslove(okResult);
});
}
// 3.在resolve_fn最后执行asynResolveList中的方法
this.asynResolveList.forEach((fn) => {
fn();
});
异步的问题解决了, 那么如何解决异步链式调用呢?
只需要对上诉方法做一点小改动即可。对返回的okResult进行一次判断,如果返回的结果是一个promise,则我们获取promise.then中的值再传回去。
if (typeof okResult === "object" && "then" in okResult) {
okResult.then((res) => {
reslove(res);
});
} else {
reslove(okResult);
}
完整代码【因为之前是用ts写的,就没有写js版本,文章中用的代码片段也是基于ts改过来的】
type RESOLVE_FN = (val: any) => void;
type REJECT_FN = (val: any) => void;
type EX_FN = (reslove: RESOLVE_FN, reject: REJECT_FN) => void;
class MyPromise {
private resolve_fn!: RESOLVE_FN;
private reject_fn!: REJECT_FN;
private status!: string;
private resolve_value!: any;
private reject_value!: any;
private asynResolveList: (() => void)[] = [];
private asynRejectList: (() => void)[] = [];
constructor(fn: EX_FN) {
this.status = "pending";
this.resolve_fn = (val) => {
if (this.status === "pending") {
this.status = "success";
this.resolve_value = val;
this.asynResolveList.forEach((fn) => {
fn();
});
}
};
this.reject_fn = (val) => {
if (this.status === "pending") {
console.log("this.reject_fn");
this.status = "fail";
this.reject_value = val;
this.asynRejectList.forEach((fn) => {
fn();
});
}
};
fn(this.resolve_fn, this.reject_fn);
}
then(reslove_then: RESOLVE_FN) {
return new MyPromise((reslove, reject) => {
if (this.status === "success") {
const okResult = reslove_then(this.resolve_value);
reslove(okResult);
}
if (this.status === "fail") {
reject(this.reject_value);
}
// 则表示是异步的
if (this.status === "pending") {
this.asynResolveList.push(() => {
const okResult: any = reslove_then(this.resolve_value);
// okResult的返回结果如果是promise
if (typeof okResult === "object" && "then" in okResult) {
okResult.then((res) => {
reslove(res);
});
} else {
reslove(okResult);
}
});
}
});
}
catch(reject_catch: REJECT_FN) {
return new MyPromise((reslove, reject) => {
if (this.status === "fail") {
const failResult = reject_catch(this.reject_value);
reject(failResult);
}
if (this.status === "success") {
reslove(this.resolve_value);
}
if (this.status === "pending") {
this.asynRejectList.push(() => {
const failResult: any = reject_catch(this.reject_value);
console.log("this", failResult);
if (typeof failResult === "object" && "then" in failResult) {
failResult.catch((error) => {
reject(error);
});
} else {
reject(failResult);
}
});
}
});
}
}
感谢阅读,如有收获,别忘记点个赞哈!!!!