前言
今天翻之前的面经时看到了虎牙的面试官问过我怎么实现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内部就可以对函数进行各种各样的控制,比如说
这个故事告诉我们,在计算机中,没有什么是不能多加一个中间层搞定的,如果有,就多加几个
啊哈
不管怎么说,思路还是比较清晰的,虽然代码实现略微复杂,但是思路在那,慢慢看就可以看懂了