最近买了掘金小册,里面有关于promise的实现。看了半天,终于理解简单的promise。而且我相信工作中也不会说让你完整实现一个。所以我在理解原理之后,我就不再深入了。
1、promise的规范
这里主要是Promise/A+ 规范,但是从简单promise上去理解,实际上我们需要知道的是三个状态
const pending = 'pending'; //等待
const resolved = 'resolved'; //成功
const rejected = 'rejected'; //失败很简单的三个状态。
2、自己想想promise是怎样实现的
我在没有实现函数之前是这样想的。
1、本身是链式调用
2、链式调用和回调函数类似
核心在于和回调函数类似。promise实际上也是类似的操作方式。
回顾下回调函数:回调函数是在当你的操作或者结果需要到达这个执行结果的时候你把函数当作参数的形式执行,然后可以得到结果。
说白了就是在恰达的时机去执行你的函数。
这里来一个简单的回调函数。看看
function huidiao(a, callback) {
callback(a * 10);
}
huidiao(20, e => {
console.log(e);
});3、开始实践
1、实现一个函数
function MyPromise(fn) {
const that = this;
that.state = pending;
that.value = null;
that.resolvedCallbacks = [];
that.rejectedCallbacks = [];
//成功的回调函数
// 失败的回调函数
}这里this不需要我解释吧。
value是到时候的执行结果
下面两个为什么是数组呢?这里肯定有人会疑问,我提前说一下,这里是放成功执行函数和失败执行函数的。
2、实现一下resolve和reject
//成功的回调函数
function resolve(value) {
if(that.state === pending) {
that.state = resolved;
that.value = value;
that.resolvedCallbacks.map(cb => cb(that.value));
}
}
// 失败的回调函数
function reject(value) {
if(that.state === pending) {
that.state = rejected;
that.value = value;
that.rejectedCallbacks.map(cb => cb(that.value));
}
}这里能看到会有传入值,还有是执行函数,和改变状态。
改变状态和给值不必多说,至于为什么是对数组进行map然后执行是因为后面会存放进来函数,函数需要执行。
埋个坑。后面解释
3、执行回调函数
try {
fn(resolve, reject)
} catch (e) {
reject(e);
}4、实现then函数
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r };
if (that.state === pending) {
that.resolvedCallbacks.push(onFulfilled);
that.rejectedCallbacks.push(onRejected);
}
if (that.state === resolved) {
onFulfilled(that.value);
}
if (that.state === rejected) {
onRejected(that.value);
}
};这里onFulfilled, onRejected是规范里面的命名方式,判断是否是函数是为了阻止非回调函数的执行
5、执行一下看看
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 0)
}).then((value) => {
console.log(value)
});结果是正常输出1
4、执行顺序解析
看了上面一堆代码是不是不理解,也感觉懵逼呢?
这里我来讲一下执行顺序,大家就理解了。
1、根据链式调用顺序,先会执行then的方法。这时候是肯定是会执行到pending状态,那么就会把
(value) => {
console.log(value)
}传入resolvedCallbacks给进入数组当中
2、函数解析的时候是会把预先定义好的变量等都完成,函数也会提前解析好,关键是在这里会执行回调函数
try {
fn(resolve, reject)
} catch (e) {
reject(e);
}上文中
setTimeout(() => {
resolve(1)
}, 0)是被fn()函数执行了。注意是通过resolve执行传入结果。这里本身是回调函数的概念。
2、resolve函数得到结果,判断之后发现当前状态是等待状态那么就会执行对应的结果
3、最后通过链式调用的回调方式来得到结果
4、至于为什么是数组或者这么多状态,那是因为我们还有catch方法。如果直接就执行了,那么就结果不对了。
4、致谢
代码本身根据《前端面试之道》小册来编写。
推广下我的摸鱼群:797957786