不知道为什么最近突然想到了关于promise的问题,如果交给我实现应该怎么实现。说实话这个问题在以前的面试中被问过,那个时候还能流畅的答出来,现在基本在实际业务中很少用到Promise,所以一时半会没想起来应该怎么实现。这怎么能行!作为一个优秀的前端【滑稽】,这种小case应该手到擒来,所以接下来将一边思考,一边写下promise的实现流程。
Promise的基本用法
首先来看看Promise的基本用法,不熟悉的话可以先看看阮一峰老师的ES6promise教程。
1 2 3 4 5
| new Promise((resolve, reject) => { setTimeout(() => { resolve('hello world') }) })
|
构造函数Promise
需要传入一个函数handle
,该函数又有两个参数resolve
和reject
。接下来看看如何来实现一个简单的Promise
Promise的基本实现
根据Promise
的A+规范,Promise
有三种状态pending
、fulfilled
和rejected
,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) } } 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