前言
今天翻之前的面经时看到了虎牙的面试官问过我怎么实现promise
,当时我没答出then
的实现(有一说一我是没想到会实习会问这个的orz)
那今天就顺手回顾一下
实现思路
完整的实现思路我在我之前的博客写过了
可以看这里:https://www.sakura-snow.com/archives/180
这里只对关键部分的代码做介绍
先贴代码,你可以先翻到下面看思路
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
| const MyPromise = (function () { const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; const PromiseValue = Symbol("PromiseValue"); const PromiseStatus = Symbol("PromiseStatus"); const onFulfilledList = Symbol("onFulfilledList"); const onRejectedList = Symbol("onRejectedList"); const updateStatus = Symbol("updateStatus"); const executeAsync = Symbol("executeAsync"); const createLinkPromise = Symbol("createLinkPromise"); const settleHandle = Symbol("settleHandle"); const execute = Symbol("execute"); const defaultOnFulfilled = function (data) {return data}; const defaultOnRejected = function (err) {throw new Error(err)}; return class MyPromise{
[executeAsync] (handler, ...arg) { setTimeout(function () { handler(...arg); }, 0) }
[updateStatus] (newStatus, newValue, executeQueue) { if (this[PromiseStatus] !== PENDING) return; this[PromiseStatus] = newStatus; this[PromiseValue] = newValue; executeQueue.forEach((handler) => { this[executeAsync] (handler, newValue); }) }
[settleHandle] (handler, immediatelyStatus, queue) { if (typeof handler !== "function") return; if (this[PromiseStatus] === immediatelyStatus) { this[executeAsync] (handler, this[PromiseValue]); } else { queue.push(handler); } }
[execute] (data, handler, resolve, reject) { try { const result = handler(data); if (result instanceof MyPromise) { result.then((data) => { resolve(data); }, (err) => { reject(err); }) }else { resolve(result); } }catch (e) { reject(e); } }
[createLinkPromise] (onFulfilled, onRejected) { return new MyPromise((resolve, reject) => { this[settleHandle]((data) => { this[execute](data, onFulfilled, resolve, reject); }, RESOLVED, this[onFulfilledList]); this[settleHandle]((err) => { this[execute](err, onRejected, resolve, reject); }, REJECTED, this[onRejectedList]); }); } then(onFulfilled = defaultOnFulfilled, onRejected = defaultOnRejected) { return this[createLinkPromise](onFulfilled, onRejected); } catch(onRejected) { return this.then(defaultOnFulfilled, onRejected); } finally(handler) { return this.then(handler, handler); } constructor(executor) { this[PromiseStatus] = PENDING; this[PromiseValue] = undefined; this[onFulfilledList] = []; this[onRejectedList] = []; const resolve = (data) => { this[updateStatus](RESOLVED, data, this[onFulfilledList]); }; const reject = (reason) => { this[updateStatus](REJECTED, reason, this[onRejectedList]); }; try { executor && executor(resolve, reject); }catch (e) { reject(e); } } static all(promises) { let length = promises.length; let resultArr = new Array(length); let count = 0; return new MyPromise((resolve, reject) => { promises.map((promise, index) => { promise.then((data) => { count ++; resultArr[index] = data; if (count >= length) { resolve(resultArr); } }, (err) => { reject(err); }) }) }) } static race(promises) { return new MyPromise((resolve, reject) => { promises.forEach((promise) => { promise.then((data) => { resolve(data); }, (err) => { reject(err); }) }) }); } static resolve(data) { if (data instanceof MyPromise) return data; return new MyPromise((resolve) => { resolve(data); }) } static reject(err) { if (err instanceof MyPromise) return err; return new MyPromise((resolve, reject) => { reject(err); }) } } })();
|
constructor
这里做了两件事
这里有必要介绍一下resovle
和reject
的实现
先来看一看updateStatus
是什么
updateStatus
做的事很简单
- 更新当前Promise的状态
- 更新状态后把对应队列中的回调函数取出来执行
then
我们先不考虑then
串联的情况,在只能then
一次时,then
需要做下面的处理
- 如果
Promise
的状态已经是resolved
或者rejected
,立即执行回调
- 否则,把回调保存到相应的队列中,等待
Promise
的状态变化再执行
值的注意的是,这里的this
,是指向前一个Promise
,而不是新返回的那个Promise
我选中的函数就是推入到队列中的回调
串联then
串联then
是通过下面的过程
- 前一个
Promise
变为resolved
或者rejected
状态时,会调用添加到队列里的函数
- 执行回调函数时,可以拿到
Promise.then
里传入的onFulfilled
,onRejected
还有resolve
和reject
onFulfilled
,onRejected
是前一个Promise
变为变为resolved
或者rejected
状态时要调用的回调函数
resolve
和reject
用于改变返回的Promise
的函数的状态(就是constructor
)里的resolve
和reject
- 如果
onFulfilled
,onRejected
返回一个普通值,直接调用resolved
或者rejected
并且传入返回值就可以了
- 如果
onFulfilled
,onRejected
返回的是一个Promise
,就要给onFulfilled
,onRejected
返回的Promise
通过then
注册一个回调(可以通过注册的回调中看出,它会拿到返回的Promise
调用resolve
或者reject
时传入的值)
看不懂嘛,其实简单来说就是
then
的onFulfilled
会被包裹一层注册到前一个Promise
的队列中,前一个Promise
的状态变化后执行被包裹的函数,被包裹的函数会执行onFulfilled
,然后处理onFulfilled
返回值并且调用下一个Promise
的resolve
后记
其实你会发现,整个实现流程中,你传入的函数并不是直接执行的,都是会经过相应地包装,这样Promise
内部就可以对函数进行各种各样的控制,比如说
这个故事告诉我们,在计算机中,没有什么是不能多加一个中间层搞定的,如果有,就多加几个
啊哈
不管怎么说,思路还是比较清晰的,虽然代码实现略微复杂,但是思路在那,慢慢看就可以看懂了