├── promise.js └── README.md /promise.js: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | function Promise(fn) { 3 | var state = 'pending', 4 | value = null, 5 | reason = null, 6 | callbacks = [], 7 | errCallbacks = []; 8 | 9 | function isFunction (fn) { 10 | return Object.prototype.toString.call(fn) === '[object Function]'; 11 | } 12 | 13 | this.then = function (onFulfilled, onRejected) { 14 | return new Promise(function (resolve, reject) { 15 | 16 | function handle(value) { 17 | var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 18 | // 当ret为promise对象时,手动执行.then方法 19 | if(ret && isFunction(ret.then)) { 20 | ret.then(function(value){ 21 | resolve(value); 22 | }); 23 | } else { 24 | resolve(ret); 25 | } 26 | } 27 | 28 | function errback(reason) { 29 | reason = isFunction(onRejected) && onRejected(reason) || reason; 30 | reject(reason); 31 | } 32 | 33 | if (state === 'pending') { 34 | callbacks.push(handle); 35 | errCallbacks.push(errback); 36 | } else if (state === 'fulfilled') { 37 | handle(value); 38 | } else if (state === 'rejected') { 39 | errback(reason); 40 | } 41 | }); 42 | }; 43 | 44 | function resolve(newValue) { 45 | value = newValue; 46 | state = 'fulfilled'; 47 | setTimeout(function () { 48 | callbacks.forEach(function (callback) { 49 | callback(value); 50 | }); 51 | }, 0); 52 | } 53 | 54 | function reject(newReason) { 55 | reason = newReason; 56 | state = 'rejected'; 57 | setTimeout(function () { 58 | callbacks.forEach(function (callback) { 59 | callback(reason); 60 | }); 61 | }, 0); 62 | } 63 | 64 | fn(resolve); 65 | } 66 | window.Promise = Promise; 67 | })(window) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ### promise实现 3 | 4 | 我们通过逆推法,一步步去实现promise。 5 | 6 | 首先观察promise的用法,如下: 7 | ```javascript 8 | const promsie = new Promsie((resolve, reject) => { 9 | if ... 10 | resolve(xx); 11 | else 12 | reject(xx); 13 | }) 14 | 15 | promise.then((value) => { 16 | ... 17 | }); 18 | ``` 19 | 20 | 通过观察上面的用法,我们大概可以做一下猜想: 21 | 1. `Promsie`是一个function,且接收一个回调函数为参数 22 | 2. `Promsie`对象有一个`then`方法,`then`方法接收一个回调函数为参数 23 | 3. `resolve`和`reject`方法,执行的时候,会将参数带给`then`方法中的回调函数,并触发执行 24 | 25 | 因此我们可以得到以下代码: 26 | ```javascript 27 | function Promise(fn) { 28 | var value = null, 29 | callbacks = []; // callbacks为数组,因为可能同时有很多个回调 30 | 31 | this.then = function (onFulfilled) { 32 | callbacks.push(onFulfilled); 33 | return this; // 以便可以进行链式操作 34 | }; 35 | 36 | function resolve(value) { 37 | callbacks.forEach(function (callback) { 38 | callback(value); 39 | }); 40 | } 41 | 42 | fn(resolve); 43 | } 44 | ``` 45 | 46 | 上述代码可能还存在一个问题:如果在then方法注册回调之前,resolve函数就执行了,怎么办? 47 | 48 | 比如promise内部的函数是同步函数: 49 | ```javascript 50 | const dosomething = () => { 51 | return new Promise(function (resolve) { 52 | resolve(123); 53 | }); 54 | } 55 | dosomething().then(function (id) { 56 | ... 57 | }); 58 | ``` 59 | 我们可以给resolve函数添加一个延时执行,首先我们想到的是`setTimeout(fn, 0);` 60 | ```javascript 61 | function resolve(value) { 62 | setTimeout(function() { 63 | callbacks.forEach(function (callback) { 64 | callback(value); 65 | }); 66 | }, 0); 67 | } 68 | ``` 69 | 70 | 如果Promise异步操作已经成功,这时,在异步操作成功之前注册的回调都会执行,但是在Promise异步操作成功这之后调用的then注册的回调就再也不会执行了,此时我们必须引入状态机制。 71 | 72 | 首先明白状态机制是啥? 73 | > Promises/A+ 2.1规范 74 | >> pending可以转化为fulfilled或rejected并且只能转化一次,也就是说如果pending转化到fulfilled状态,那么就不能再转化到rejected。并且fulfilled和rejected状态只能由pending转化而来,两者之间不能互相转换。 75 | 76 | 经过改进之后,我们的代码如下: 77 | ```javascript 78 | function Promise(fn) { 79 | var state = 'pending', 80 | value = null, 81 | callbacks = []; 82 | 83 | this.then = function (onFulfilled) { 84 | return new Promise(function (resolve) { 85 | function handle(value) { 86 | var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 87 | resolve(ret); 88 | } 89 | if (state === 'pending') { 90 | callbacks.push(handle); 91 | } else if(state === 'fulfilled'){ 92 | handle(value); 93 | } 94 | }); 95 | }; 96 | 97 | function resolve(newValue) { 98 | value = newValue; 99 | state = 'fulfilled'; 100 | setTimeout(function () { 101 | callbacks.forEach(function (callback) { 102 | callback(value); 103 | }); 104 | }, 0); 105 | } 106 | 107 | fn(resolve); 108 | } 109 | ``` 110 | 111 | 那么这里问题又来了,如果用户再then函数里面注册的仍然是一个Promise,如下: 112 | ```javascript 113 | const dosomethingmore = (value) => { 114 | return new Promise((resolve) => { 115 | ... 116 | resolve(newValue); 117 | }); 118 | } 119 | 120 | dosomething() 121 | .then(dosomethingmore) 122 | .then((value) => { 123 | ... 124 | }); 125 | ``` 126 | 这就是所谓的链式Promise。 127 | 128 | > 链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise 129 | 130 | 经过改进,我们得到如下代码: 131 | ```javascript 132 | function Promise(fn) { 133 | var state = 'pending', 134 | value = null, 135 | callbacks = []; 136 | 137 | var isFunction = function(fn) { 138 | return Object.prototype.toString.call(fn) === '[object Function]'; 139 | } 140 | 141 | this.then = function (onFulfilled) { 142 | return new Promise(function (resolve) { 143 | function handle(value) { 144 | var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 145 | // 当ret为promise对象时,手动执行.then方法 146 | if(ret && typeof isFunction(ret.then)) { 147 | ret.then(function(value){ 148 | resolve(value); 149 | }); 150 | } else { 151 | resolve(ret); 152 | } 153 | } 154 | if (state === 'pending') { 155 | callbacks.push(handle); 156 | } else if(state === 'fulfilled') { 157 | handle(value); 158 | } 159 | }); 160 | }; 161 | 162 | function resolve(newValue) { 163 | value = newValue; 164 | state = 'fulfilled'; 165 | setTimeout(function () { 166 | callbacks.forEach(function (callback) { 167 | callback(value); 168 | }); 169 | }, 0); 170 | } 171 | 172 | fn(resolve); 173 | } 174 | ``` 175 | 176 | 我们继续加入失败的状态,得到如下代码: 177 | ```javascript 178 | function Promise(fn) { 179 | var state = 'pending', 180 | value = null, 181 | reason = null, 182 | callbacks = [], 183 | errCallbacks = []; 184 | 185 | function isFunction (fn) { 186 | return Object.prototype.toString.call(fn) === '[object Function]'; 187 | } 188 | 189 | this.then = function (onFulfilled, onRejected) { 190 | return new Promise(function (resolve, reject) { 191 | function handle(value) { 192 | var ret = isFunction(onFulfilled) && onFulfilled(value) || value; 193 | // 当ret为promise对象时,手动执行.then方法 194 | if(ret && isFunction(ret.then)) { 195 | ret.then(function(value){ 196 | resolve(value); 197 | }); 198 | } else { 199 | resolve(ret); 200 | } 201 | } 202 | function errback(reason) { 203 | reason = isFunction(onRejected) && onRejected(reason) || reason; 204 | reject(reason); 205 | } 206 | if (state === 'pending') { 207 | callbacks.push(handle); 208 | errCallbacks.push(errback); 209 | } else if (state === 'fulfilled') { 210 | handle(value); 211 | } else if (state === 'rejected') { 212 | errback(reason); 213 | } 214 | }); 215 | }; 216 | 217 | function resolve(newValue) { 218 | value = newValue; 219 | state = 'fulfilled'; 220 | setTimeout(function () { 221 | callbacks.forEach(function (callback) { 222 | callback(value); 223 | }); 224 | }, 0); 225 | } 226 | 227 | function reject(newReason) { 228 | reason = newReason; 229 | state = 'rejected'; 230 | setTimeout(function () { 231 | callbacks.forEach(function (callback) { 232 | callback(reason); 233 | }); 234 | }, 0); 235 | } 236 | 237 | fn(resolve); 238 | } 239 | ``` 240 | --------------------------------------------------------------------------------