mypromise.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * @Author: Marte
  3. * @Date: 2018-09-26 18:28:43
  4. * @Last Modified by: Marte
  5. * @Last Modified time: 2018-10-31 23:51:36
  6. */
  7. (function(window){
  8. // 参考Joe-Xie:https://www.cnblogs.com/XieJunBao/p/9156134.html
  9. // 原生封装promise为了应对低版本浏览器不兼容问题
  10. // 异步串行思路:promise执行then是注册回调函数,then有多个就可以注册多个回调函数,但是若多个回调都是异步执行的,那我们要等上一个异步结束后才执行下一个异步,这是时候就需要上一个异步操作完成后,把这个完成状态告诉下一个回调,这样才可以异步串行。为了解决这个问题我们把异步完成状态托管给promise去管理
  11. // 流程:第一步注册:链式调用then函数,每执行一个then函数,返回一个桥梁promise(then函数中的成功回调和失败回调是写入这个promise的回调列表中的,注意成功回调的功能除了执行本身函数外还要更新下一个promise的状态)
  12. // 第二步执行:第一个promise的异步执行完,开始执行第一个promise的回调函数(回调函数又分两步走:第一步:resolvePromise解析回调返回值(如果是promise则说明是异步,就需要继续解析直到不是promise而是一个具体的值),第二步:当回调返回的值是一个具体值而不是promise时,调用第二个proomise的reslove方法将第二个proomise的状态更新为fulfilled,并将第一个promise的回调的值传入p2的回调函数中去执行)
  13. function MyPromise(fn) {
  14. var self = this;
  15. // 成功回调传的参数
  16. self.value = null;
  17. // 失败回调传的参数
  18. self.error = null;
  19. // 当前promise对象的状态
  20. self.status = "pending";
  21. // 存储成功回调列表
  22. self.onFulfilledCallbacks = [];
  23. // 存储失败回调列表
  24. self.onRejectedCallbacks = [];
  25. // 状态改变并执行回调
  26. // 成功
  27. function resolve(value) {
  28. // 判断传入参数是否由MyPromise构造的对象,若是,注册该函数
  29. if (value instanceof MyPromise) {
  30. return value.then(resolve, reject);
  31. }
  32. // 判断
  33. if (self.status === "pending") {
  34. setTimeout(function(){
  35. self.status = "fulfilled";
  36. self.value = value;
  37. // 执行成功回调
  38. // self.onFulfilledCallbacks.forEach(function(callback){callback(self.value)});
  39. // 向下兼容forEach
  40. for(var i=0;i<self.onFulfilledCallbacks.length;i++){
  41. self.onFulfilledCallbacks[i](self.value);
  42. }
  43. }, 0)
  44. }
  45. }
  46. // 失败
  47. function reject(error) {
  48. if (self.status === "pending") {
  49. setTimeout(function() {
  50. self.status = "rejected";
  51. self.error = error;
  52. // self.onRejectedCallbacks.forEach(function(callback){callback(self.error)});
  53. for(var i=0;i<self.onRejectedCallbacks.length;i++){
  54. self.onRejectedCallbacks[i](self.error);
  55. }
  56. }, 0)
  57. }
  58. }
  59. try {
  60. fn(resolve, reject);
  61. }
  62. catch (e) {
  63. reject(e);
  64. }
  65. }
  66. // 解析放回值
  67. // 用来解析回调函数的返回值x,x可能是普通值也可能是个promise对象
  68. // 因为回调函数既可能会返回一个异步的promise也可能会返回一个同步结果,所以我们把直接把回调函数的结果托管给bridgePromise,使用resolvePromise方法来解析回调函数的结果,如果回调函数返回一个promise并且状态还是pending,就在这个promise的then方法中继续解析这个promise reslove传过来的值,如果值还是pending状态的promise就继续解析,直到不是一个异步promise,而是一个正常值就使用bridgePromise的reslove方法将bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入,到此异步操作就衔接上了。
  69. function resolvePromise(bridgepromise, x, resolve, reject) {
  70. // bridgepromise是桥梁promise,x是桥梁promise中注册的成功回调的返回值,resolve和reject是桥梁promise的状态改变函数
  71. // 2.3.1规范,避免循环引用
  72. // 如果成功回调的值又是桥梁promise就返回循环传参的错误(死循环)
  73. if (bridgepromise === x) {
  74. return reject(new TypeError('Circular reference'));
  75. }
  76. var called = false;
  77. // // 如果x是一个promise,则通过递归
  78. // if (x instanceof MyPromise) {
  79. // //如果这个promise是pending状态,就在它的then方法里继续执行resolvePromise解析它的结果,直到返回值不是一个pending状态的promise为止(这里使用了递归的方法)
  80. // if (x.status === "pending") {
  81. // x.then(
  82. // function(y){
  83. // resolvePromise(bridgepromise, y, resolve, reject);
  84. // },
  85. // function(error){
  86. // reject(error);
  87. // }
  88. // );
  89. // }
  90. // else {
  91. // x.then(resolve, reject);
  92. // }
  93. // }
  94. // else
  95. // // 如果x是一个promise,则继续解析它的状态
  96. if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) {
  97. try {
  98. var then = x.then;
  99. if (typeof then === 'function') {
  100. // then方法的指向传入的桥梁promise,也就是说该桥梁promise调用了then方法并传入了成功回调和失败回调
  101. then.call(
  102. x,
  103. // 传入then的成功回调
  104. function(y){
  105. if (called) return;
  106. called = true;
  107. // 这里重新解析当前的桥梁promise,至于成功回调的返回值传空(这里目的是通过递归持续判断当前桥梁promise的状态)
  108. resolvePromise(bridgepromise, y, resolve, reject);
  109. },
  110. //传入then的失败回调
  111. function(error){
  112. if (called) return;
  113. called = true;
  114. reject(error);
  115. }
  116. )
  117. }
  118. // 如果then不是一个函数,则以x为值改变promise状态并延长成功回调列表
  119. else {
  120. resolve(x);
  121. }
  122. }
  123. // 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
  124. catch (e) {
  125. if (called) return;
  126. called = true;
  127. reject(e);
  128. }
  129. }
  130. // 如过x不是一个promise,则改变bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入
  131. else {
  132. resolve(x);
  133. }
  134. }
  135. // 注册回调函数
  136. MyPromise.prototype.then = function(onFulfilled, onRejected) {
  137. var self = this;
  138. // 搭建桥梁promise(即调用为then方法后重新返回一个新的promise对象)
  139. var bridgePromise;
  140. // 防止使用者不传成功或失败回调函数,所以成功失败回调都给了默认回调函数
  141. onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function(value){return value};
  142. onRejected = typeof onRejected === "function" ? onRejected : function(error){throw error};
  143. // 如果当前的promise对象是完成状态
  144. // 返回一个新的桥梁promise
  145. if (self.status === "fulfilled") {
  146. return bridgePromise = new MyPromise(function(resolve, reject){
  147. setTimeout(function(){
  148. try {
  149. // 获取成功回调函数的返回值
  150. var x = onFulfilled(self.value);
  151. // 解析桥梁promise函数
  152. resolvePromise(bridgePromise, x, resolve, reject);
  153. }
  154. catch (e) {
  155. reject(e);
  156. }
  157. }, 0);
  158. })
  159. }
  160. // 如果当前的promise对象是拒绝状态
  161. if (self.status === "rejected") {
  162. return bridgePromise = new MyPromise(function(resolve, reject){
  163. setTimeout(function(){
  164. try {
  165. var x = onRejected(self.error);
  166. resolvePromise(bridgePromise, x, resolve, reject);
  167. }
  168. catch (e) {
  169. reject(e);
  170. }
  171. }, 0);
  172. });
  173. }
  174. // 如果当前的promise对象是听候状态,则在当前promise对象的成功回调列表和失败回调列表中注入
  175. if (self.status === "pending") {
  176. return bridgePromise = new MyPromise(function(resolve, reject){
  177. // 注意回调列表是把整个回调函数和回调解析函数一起注入的!!!!!,所以在执行回调时除运行回调函数还要,解析桥梁promise的状态(有可能桥梁promise中也有promise),解析中改变当前promise的状态,若当前promise的状态为完成状态才继续执行下一个注册好的回调
  178. self.onFulfilledCallbacks.push(function(value){
  179. try {
  180. var x = onFulfilled(value);
  181. resolvePromise(bridgePromise, x, resolve, reject);
  182. }
  183. catch (e) {
  184. reject(e);
  185. }
  186. });
  187. self.onRejectedCallbacks.push(function(error){
  188. try {
  189. var x = onRejected(error);
  190. resolvePromise(bridgePromise, x, resolve, reject);
  191. }
  192. catch (e) {
  193. reject(e);
  194. }
  195. });
  196. });
  197. }
  198. }
  199. MyPromise.prototype.MyCatch = function(onRejected) {
  200. return this.then(null, onRejected);
  201. }
  202. MyPromise.all = function(promises) {
  203. return new MyPromise(function(resolve, reject) {
  204. var result = [];
  205. var count = 0;
  206. for (var i = 0; i < promises.length; i++) {
  207. // (function(i){
  208. // return promises[i].then(function(data) {
  209. // result[i] = data;
  210. // if (++count == promises.length) {
  211. // resolve(result);
  212. // }
  213. // }, function(error) {
  214. // reject(error);
  215. // });
  216. // })(i)
  217. function closeTemp(i){
  218. return promises[i].then(function(data) {
  219. result[i] = data;
  220. if (++count == promises.length) {
  221. resolve(result);
  222. }
  223. }, function(error) {
  224. reject(error);
  225. });
  226. }
  227. closeTemp(i)
  228. }
  229. });
  230. }
  231. MyPromise.race = function(promises) {
  232. return new MyPromise(function(resolve, reject) {
  233. for (var i = 0; i < promises.length; i++) {
  234. promises[i].then(function(data) {
  235. resolve(data);
  236. }, function(error) {
  237. reject(error);
  238. });
  239. }
  240. });
  241. }
  242. MyPromise.resolve = function(value) {
  243. return new MyPromise(function(resolve){
  244. resolve(value);
  245. });
  246. }
  247. MyPromise.reject = function(error) {
  248. return new MyPromise(function(resolve, reject){
  249. reject(error);
  250. });
  251. }
  252. MyPromise.promisify = function(fn) {
  253. return function() {
  254. var args = Array.from(arguments);
  255. return new MyPromise(function(resolve, reject) {
  256. fn.apply(null, args.concat(function(err) {
  257. err ? reject(err) : resolve(arguments[1])
  258. }));
  259. })
  260. }
  261. }
  262. window.MyPromise = MyPromise;
  263. })(window);