promise解析

不知道为什么最近突然想到了关于promise的问题,如果交给我实现应该怎么实现。说实话这个问题在以前的面试中被问过,那个时候还能流畅的答出来,现在基本在实际业务中很少用到Promise,所以一时半会没想起来应该怎么实现。这怎么能行!作为一个优秀的前端【滑稽】,这种小case应该手到擒来,所以接下来将一边思考,一边写下promise的实现流程。

Promise的基本用法

首先来看看Promise的基本用法,不熟悉的话可以先看看阮一峰老师的ES6promise教程

1
2
3
4
5
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello world')
})
})

构造函数Promise需要传入一个函数handle,该函数又有两个参数resolvereject。接下来看看如何来实现一个简单的Promise

Promise的基本实现

根据Promise的A+规范,Promise有三种状态pendingfulfilledrejected,pending可以将Promise的状态改为fulfilled或者rejected,但是后两种状态一旦确定就不能再更改Promise的状态了。除此之外,Promise最关键的是then方法以及resolve和reject的实现。由于Promise支持链式调用,所以then方法需要返回一个新的Promise。另外,Promise支持异步调用,所以需要一个队列或者事件变量来存储回调之后的执行,这个执行只能放在resolve和reject中来执行。话不多说,let’s coding!

首先,Promise的构造函数中应该初始化一个status变量、value变量以及相应的事件回调执行队列。另外,Promise的参数为一个函数,所以需要在constructor中判断该参数是否为一个函数。所以一个Promise的构造部分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const PENDGING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

const isFunction = (func) => {
return Object.prototype.toString.call(func) === '[object Function]';
}


class MyPromise {
constructor(handle) {
if(!isFunction(handle)) {
throw new Error("promise must accept a function as a parameter")
}

this.status = PENDING;
this.value = undefined;
this.fulfilledQueue = [];
this.rejectedQueue = [];

try {
handle(this._resolve.bind(this), this._reject.bind(this));
} catch(err) {
this._reject(err);
}
}
}

上面简要实现了Promise的构造函数部分,以及在执行handle过程中使用了try catch抛出错误的部分。接下来实现一下then方法:

then方法需要注意几点,一是判断传入then中的参数是否为函数;二是传入的函数如果返回的是Promise应该怎么处理。三是需要判断此时的状态是否可以执行回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
then(onFulfilled, onRejected) {
return new MyPromise((resolveNext, rejectNext) => {
const {status, value} = this;

const runFulfill = (val) => {
try {
if(!isFunction(onFulfilled)) {
resolveNext(val);
} else {
let res = onFulfilled(val);
if(res instanceof MyPromise) {
res.then(resolveNext, rejectNext)
} else {
resolveNext(res);
}
}
} catch(err) {
rejectNext(err);
}

}
const runReject = (err) => {
try {
if(!isFunction(onRejected)) {
rejectNext(err);
} else {
let res = onRejected(err);
if(res instanceof MyPromise) {
res.then(resolveNext, rejectNext)
} else {
resolveNext(res);
}
}
} catch(err) {
rejectNext(err);
}
}


switch(status) {
case PENDING:
this.fulfilledQueue.push(runFulfill);
this.rejectedQueue.push(runReject);
break;
case FULFILLED:
runFulfill(value);
break;
case REJECTED:
runReject(value);
break;
}
})
}

接下来是resolve和reject方法,resolve需要能够改变Promise的status和value,同时执行
then方法中注册的回调,为了支持同步调用,所以还要将执行回调这一过程放入下个事件循环中去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
_resolve(val) {
if(this.status !== PENDING) return;
const run = () => {
const runFulfilled = (value) => {
let cb;
while (cb = this._fulfilledQueues.shift()) {
cb(value)
}
}

const runRejected = (error) => {
let cb;
while (cb = this._rejectedQueues.shift()) {
cb(error)
}
}
//判断val的类型
if(val instanceof MyPromise) {
val.then(value => {
this._value = value
this._status = FULFILLED
runFulfilled(value)
}, err => {
this._value = err
this._status = REJECTED
runRejected(err)
})
} else {
this._value = value
this._status = FULFILLED
runFulfilled(value)
}
}
setTimeout(run, 0);
}

至此,一个简单的Promise就完成啦~

上面的只是简单回忆了一下,可能不是很仔细。下面的链接是开始学Promise的时候看的文章,讲的过程很清楚仔细,
以后要是忘了再去看看。
相关链接: https://juejin.im/post/5b83cb5ae51d4538cc3ec354

文章作者: Junjie
文章链接: http://yoursite.com/2019/07/30/promiseAnalysis/
版权声明: 本博客所有文章除特别声明外,均采用 undefined 许可协议。转载请注明来自 Junjie's blog