现在,用回调处理一些复杂的逻辑,显得代码臃肿,难于阅读,特别是异步,嵌套。
解决这样的问题,可以是之前所说的Backbone.Events的pubsub,或者是今天要说的when.js所实现的promise。
在前端,jQuery的ajax全面改写就是为了引入promise这一套,为了使代码更流畅,更易于维护,事实上更容易实现复杂的需求。
jQuery Deferred所实现的promise并不是那么的规范,功能也并不能么全,在前端可以很方便的使用就是了,那么在后端(nodejs),我推荐
使用when.js,它的接口清晰,功能强大,架构更是很精妙,并且它在实现了完整的Promise A+后,又添加了好多扩展功能,使得在实际应用中,
能够很方便的写出优秀的代码。
所以对于这样强大的代码,当然是要去读一遍,学学作者的架构思路,花了几天时间阅读,对源代码进行了中文注释讲解(其中有放一些例子),
就贴在下面了,可能会有点长(看源代码都需要耐心嘛),如果有错误还望指证出来,多谢啦~
1 /** @license MIT License (c) copyright 2011-2013 original author or authors */ 2 3 /** 4 * A lightweight CommonJS Promises/A and when() implementation 5 * when is part of the cujo.js family of libraries (http://cujojs.com/) 6 * 7 * Licensed under the MIT License at: 8 * http://www.opensource.org/licenses/mit-license.php 9 * 10 * @author Brian Cavalier 11 * @author John Hann 12 * @version 2.7.1 13 */ 14 // 首先是规范的兼容AMD(比如requirejs)和CMD(比如nodejs) 15 (function(define) { 'use strict'; 16 define(function (require) { 17 18 // Public API 19 // 接口很明确就是以下这些 20 // 首先promise对象拥有的三个状态:pending, resolved(fulfilled), rejected 21 // 再然后需要理解promise对象和defer对象的关系 22 // 可以简单的理解为:defer对象内置了一个promise对象 23 // 它拥有两个接口resolve和reject来控制promise对象的最终的状态,从而进行异步操作的处理 24 when.promise = promise; // Create a pending promise(创建一个状态还是pending的promise对象) 25 when.resolve = resolve; // Create a resolved promise (创建一个状态已经是resolved的promise对象) 26 when.reject = reject; // Create a rejected promise(创建一个状态已经是resolved的promise对象) 27 when.defer = defer; // Create a {promise, resolver} pair(创建一个defer对象) 28 29 when.join = join; // Join 2 or more promises(解决多个promiseOrValue对象,与all想死) 30 31 when.all = all; // Resolve a list of promises(等待所有promise都resolve,新的promise才resolve) 32 when.map = map; // Array.map() for promises (类似数组的map) 33 when.reduce = reduce; // Array.reduce() for promises(类似数组的reduce) 34 when.settle = settle; // Settle a list of promises(处理promiseOrValue数组,返回state数组) 35 36 when.any = any; // One-winner race(一个promiseOrValue resolve,新的promiseresolve) 37 when.some = some; // Multi-winner race(some个promiseOrValue resolve,新的promiseresolve) 38 39 when.isPromise = isPromiseLike; // DEPRECATED: use isPromiseLike 40 when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable 41 42 /** 43 * Register an observer for a promise or immediate value. 44 * 45 * @param {*} promiseOrValue 46 * @param {function?} [onFulfilled] callback to be called when promiseOrValue is 47 * successfully fulfilled. If promiseOrValue is an immediate value, callback 48 * will be invoked immediately. 49 * @param {function?} [onRejected] callback to be called when promiseOrValue is 50 * rejected. 51 * @param {function?} [onProgress] callback to be called when progress updates 52 * are issued for promiseOrValue. 53 * @returns {Promise} a new {@link Promise} that will complete with the return 54 * value of callback or errback or the completion value of promiseOrValue if 55 * callback and/or errback is not supplied. 56 */ 57 58 // 官方的解释是:为一个promise对象或者立即数注册一个观察者 59 // 其实简单点就是 60 // 当promiseOrValue为resolved状态时,onRejected回调被调用 61 // 1. 当promiseOrValue被resolve时,onFulfilled回调被调用 62 // 2. 当promise为reject状态时,onRejected回调被调用 63 // 3. 当promise为notify状态时,onProgress回调被调用 64 // 注意: 65 // 上述的第一点用的promiseOrValue,这里的value指的是立即数,立即数使得生成promise对象开始就是resolved状态 66 // 另外这里的promiseOrValue也可以是一个数组(即[promiseOrValue1, promiseOrValue2, ...]) 67 function when(promiseOrValue, onFulfilled, onRejected, onProgress) { 68 // Get a trusted promise for the input promiseOrValue, and then 69 // register promise handlers 70 // 首先这里先对promiseOrValue进行转换(cast方法),将其转变为promise对象 71 // 然后调用promise对象的then方法,并将用户提供的参数传递给then方法,等待被调用 72 // 最后返回then方法创建的新的promise对象,这样来维持链式 73 // 而且onFulfilled一般是函数,返回的值将作为形参传递给下一个onFulfilled, 74 // 但如果不是函数那么onFulfilled的理应接受的参数将继续传递给下一个onFulfilled, 75 // 也就是说可以继续这样调用: 76 // when('hello', 'notFunction').then(function (v) { 77 // console.log(v);// 这里的v就是hello 78 // }); 79 return cast(promiseOrValue).then(onFulfilled, onRejected, onProgress); 80 } 81 82 /** 83 * Creates a new promise whose fate is determined by resolver. 84 * @param {function} resolver function(resolve, reject, notify) 85 * @returns {Promise} promise whose fate is determine by resolver 86 */ 87 // 创建一个promise对象,它的最终状态又resolver函数决定,为什么? 88 // 因为resovler函数作为用户自定义函数会被传递三个形参,就是promise对象的三个内置改变状态的接口 89 // when.promise(function (reslove, reject, notify) { 90 // resolve('xxx'); // fn1 被调用 91 // //reject('xxx'); // fn2 被调用 92 // //notify('xxx'); // fn3 被调用 93 94 // }).then(fn1, fn2, fn3); 95 function promise(resolver) { 96 // 实质是调用Promise构造函数 97 // 这里的PromiseStatus不是很清楚,好像是when/monitor下的文件,应该是辅助文件吧, 98 // 可以先不用管 99 return new Promise(resolver, 100 monitorApi.PromiseStatus && monitorApi.PromiseStatus()); 101 } 102 103 /** 104 * Trusted Promise constructor. A Promise created from this constructor is 105 * a trusted when.js promise. Any other duck-typed promise is considered 106 * untrusted. 107 * @constructor 108 * @returns {Promise} promise whose fate is determine by resolver 109 * @name Promise 110 */ 111 // Promise构造器 112 // resolver上面已经说过,是一个函数 113 // status暂时先不管,跟程序主体关系不大 114 function Promise(resolver, status) { 115 var self, value, consumers = []; 116 117 self = this; 118 this._status = status; 119 this.inspect = inspect; 120 this._when = _when; 121 122 // Call the provider resolver to seal the promise's fate 123 // 调用使用者提供的resolver函数,并将操作该promise对象“命运”的三个接口函数传递给resolver函数 124 // 利用try catch 捕获异常,毕竟resolver函数是使用者自定义的 125 // 如果异常将该promise对象reject 126 // 其实这里是有些疑问的?如果该异常出现在promise对象resolve或者reject之后, 127 // 这里catch里的reject就毫无用处了(毕竟promise的最终状态是不可以改变的) 128 try { 129 resolver(promiseResolve, promiseReject, promiseNotify); 130 } catch(e) { 131 promiseReject(e); 132 } 133 134 /** 135 * Returns a snapshot of this promise's current status at the instant of call 136 * @returns {{state:String}} 137 */ 138 // inspect函数用来查看当前promise对象的状态以及相关的值 139 function inspect() { 140 //这里的value有三种情况: 141 // pending时,为undefined 142 // resolved时,是FulfilledPromise的实例 143 // rejected时,是FulfilledPromise的实例 144 // 所以在非空时这才有了对应的inspect方法 145 return value ? value.inspect() : toPendingState(); 146 } 147 148 /** 149 * Private message delivery. Queues and delivers messages to 150 * the promise's ultimate fulfillment value or rejection reason. 151 * @private 152 */ 153 // 这里的_when私有函数起到至关重要的作用。 154 // 这里它利用consumers和enqueue数组存储经过封装后的callback,不同的是: 155 // consumers里的callback是等待该promise对象resolve或者reject后执行 156 // enqueue里的callback是等待下个tick执行,或者说是延时执行(此时该promise对象已经resolved或者rejected了) 157 // 另外巧妙通过闭包实现了对onFulfilled,onRejected,onProgress的访问, 158 // 而无需像jQuery Deferrred那样通过创建维护三个队列存储callback 159 function _when(resolve, notify, onFulfilled, onRejected, onProgress) { 160 // 通过consumers参数判断该promise对象是否已经有了最终状态(即resolved或者rejected) 161 // resloved(rejected)了,加入队列在下一个时间周期等待执行 162 // pending状态,存储起来在,等待适当的时候被执行(reslove或者reject的时候) 163 consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); }); 164 165 function deliver(p) { 166 // 这里的p依然有三种值 167 // 1. 处于pending状态的promise对象 168 // 这种情苦发生在onFulfilled返回一个处于pending状态的promie对象, 169 // 利用p._when关联之后的promise对象从而继续完成同步操作 170 // 如:(虽然异步,但是却是同步的写法,免去了callback的嵌套) 171 // when.promise(function () { 172 // var defer = when.defer(); 173 // setTimout(function () { 174 // defer.resolve('xx'); 175 // }, 50) 176 // }).then(function (val) { 177 // console.log(val); // xx 178 // }); 179 // 2. FulfilledPromise对象 180 // 3. RejectedPromise对象 181 // 所以这里的p._when调用的方法出处各有不同 182 p._when(resolve, notify, onFulfilled, onRejected, onProgress); 183 } 184 } 185 186 /** 187 * Transition from pre-resolution state to post-resolution state, notifying 188 * all listeners of the ultimate fulfillment or rejection 189 * @param {*} val resolution value 190 */ 191 // 当前promise对象的resolve接口 192 function promiseResolve(val) { 193 // val的值可以是有四种值 194 // 1. 立即数(经过coerce处理最终变为FulfilledPromise对象) 195 // 2. promise对象 196 // 3. RejectedPromise对象(仅供内部传递,因为RejectedPromise是未暴露的函数类) 197 // 3. FulfilledPromise对象(仅供内部传递) 198 // 同样给出一个例子: 199 // when.promise(function (resolve) { 200 201 // // resolve('hello'); // 情况一立即数 202 203 // var defer = when.defer(); 204 205 // setTimeout(function () { // 情况二promise对象,同样可以将setTimeout去掉试试 206 // defer.resolve('hello'); 207 // // defer.reject('hello'); 208 // }, 200); 209 210 // resolve(defer.promise); 211 // }).then(function (value) { 212 // console.log(value); // hello 213 // }); 214 215 // consumers用来判断promise对象是否有了最终状态(即pending->resolved/rejected) 216 // 因为根据Promises/A+规范规定,prmoise对象的最终状态是不可变的 217 // 也就是说resolve和reject只会被执行一次 218 if(!consumers) { 219 return; 220 } 221 222 // 将consumers置为undefined表示promise对象已经resolve或者reject了 223 var queue = consumers; 224 consumers = undef; 225 226 // 将当前要执行的任务入队列,等待下一个时刻执行,将异步进行到底 227 enqueue(function () { 228 // coerce进行val的转换 229 // 转换为promise对象或者promise的子类RejectedPromise/FulfilledPromise的实例 230 // 传递给value,value很重要,作为最终的值,之后回通过必包传递给一个关联回调 231 value = coerce(self, val); 232 if(status) { 233 updateStatus(value, status); 234 } 235 // 运行consumers里传递过来的函数队列 236 runHandlers(queue, value); 237 }); 238 } 239 240 /** 241 * Reject this promise with the supplied reason, which will be used verbatim. 242 * @param {*} reason reason for the rejection 243 */ 244 // 当前promise对象的reject接口 245 // 实质还是利用resolve的接口,只不过是主动传递RejectedPromise的实例 246 function promiseReject(reason) { 247 promiseResolve(new RejectedPromise(reason)); 248 } 249 250 /** 251 * Issue a progress event, notifying all progress listeners 252 * @param {*} update progress event payload to pass to all listeners 253 */ 254 // notify就是一个进度提示,这在做一些进度方面的组件是很有用户体验的,比如flash uploader 255 // 显然既然是进度,那么首先promise对象是必须还处于pending状态,notify才会有效 256 // 所以consumers必须不为空 257 // 给个例子: 258 // when.promise(function (resolve, reject, notify) { 259 260 // var counter = 0; 261 // var timer = setInterval(function () { 262 // counter++; 263 // notify(counter); 264 265 // if (counter === 10) { 266 // resolve('over'); 267 // clearInterval(timer); 268 // } 269 // }, 1); 270 // }).then(function (value) { 271 // console.log(value); 272 // }, undefined, function (update) { 273 // console.log(update); 274 // }); 275 // 结果是 1 2 3 4 5 6 7 8 9 10 over 276 function promiseNotify(update) { 277 if(consumers) { 278 var queue = consumers; 279 enqueue(function () { 280 runHandlers(queue, new ProgressingPromise(update)); 281 }); 282 } 283 } 284 } 285 286 // 接下来是Promise的原型方法,最重要的就是then方法 287 promisePrototype = Promise.prototype; 288 289 /** 290 * Register handlers for this promise. 291 * @param [onFulfilled] {Function} fulfillment handler 292 * @param [onRejected] {Function} rejection handler 293 * @param [onProgress] {Function} progress handler 294 * @return {Promise} new Promise 295 */ 296 // then方法是Promises/A+的核心,也是链式的关键,用来注册三种回调 297 // 通过调用_when的私有方法能做到以下几点: 298 // 1. 进行callback的注册 299 // 2. 创建新的promise对象(newPromise)并返回,继续链式下去 300 // 3. 将newPromise对象的决定权(即三个内置接口)交付给调用then方法的promise对象(即与之关联在一起) 301 promisePrototype.then = function(onFulfilled, onRejected, onProgress) { 302 var self = this; 303 304 return new Promise(function(resolve, reject, notify) { 305 self._when(resolve, notify, onFulfilled, onRejected, onProgress); 306 }, this._status && this._status.observed()); 307 }; 308 309 /** 310 * Register a rejection handler. Shortcut for .then(undefined, onRejected) 311 * @param {function?} onRejected 312 * @return {Promise} 313 */ 314 // 很明显内部调用了then方法,只传递了onRejected函数 315 // 其实相当于promise.then(undef, onRejected)的快捷键 316 promisePrototype['catch'] = promisePrototype.otherwise = function(onRejected) { 317 return this.then(undef, onRejected); 318 }; 319 320 /** 321 * Ensures that onFulfilledOrRejected will be called regardless of whether 322 * this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT 323 * receive the promises' value or reason. Any returned value will be disregarded. 324 * onFulfilledOrRejected may throw or return a rejected promise to signal 325 * an additional error. 326 * @param {function} onFulfilledOrRejected handler to be called regardless of 327 * fulfillment or rejection 328 * @returns {Promise} 329 */ 330 // finally和ensure方法保证promise对象无论什么状态的情况下,最终都会执行onFulfilledOrRejected 331 // 但是onFulfilledOrRejected是不带任何参数的 332 // 另外,finally(ensure)方法如果后面继续链式,添加then方法,最终执行是与该promise对象相关的,并且接受 333 // promise对象的resolve的value值和reject的reason值(与finally的返回值无关,除非onFulfilledOrRejected 334 // 回调报出异常或者返回rejected的promise对象) 335 // 举个例子: 336 // var when = require('when'); 337 // var defer = when.defer(); 338 339 // defer.promise.finally(function () { 340 // console.log(arguments); // {} 341 342 // var defer2 = when.defer(); 343 // defer2.reject('xxx'); 344 345 // return defer2.promise; 346 // }).then(function (value) { 347 // console.log('value: ' + value); 348 // }, function (reason) { 349 // console.log('reason: ' + reason); // reason: xxx 350 // }); 351 // defer.resolve('hello'); 352 promisePrototype['finally'] = promisePrototype.ensure = function(onFulfilledOrRejected) { 353 // 这里利用yield(this),试图将接下来的newPromise对象的控制权交给当前的promise对象 354 return typeof onFulfilledOrRejected === 'function' 355 ? this.then(injectHandler, injectHandler)['yield'](this) 356 : this; 357 358 function injectHandler() { 359 // 这里是为了配合yield方法,试图想返回一个resolved的promise对象 360 // 但是onFulfilledOrRejected(),如果发生异常,或者返回rejectedpromise对象 361 // 将会使得结果与当前promise对象的状态无关了,就像上面代码没有输出hello一样 362 return resolve(onFulfilledOrRejected()); 363 } 364 }; 365 366 /** 367 * Terminate a promise chain by handling the ultimate fulfillment value or 368 * rejection reason, and assuming responsibility for all errors. if an 369 * error propagates out of handleResult or handleFatalError, it will be 370 * rethrown to the host, resulting in a loud stack track on most platforms 371 * and a crash on some. 372 * @param {function?} handleResult 373 * @param {function?} handleError 374 * @returns {undefined} 375 */ 376 // done方法有两个作用: 377 // 1. 结束链式 378 // 2. 异常处理 379 // 如下: 380 // var when = require('when'); 381 // var defer = when.defer(); 382 383 // defer.promise.done(function () { 384 // console.log(arguments) 385 // }, function (value) { 386 // var defer = when.defer(); 387 // defer.reject(value) 388 // return defer.promise(); 389 // }); 390 // defer.reject('world'); 391 // 将会报出程序异常,结束程序执行 392 promisePrototype.done = function(handleResult, handleError) { 393 this.then(handleResult, handleError)['catch'](crash); 394 }; 395 396 /** 397 * Shortcut for .then(function() { return value; }) 398 * @param {*} value 399 * @return {Promise} a promise that: 400 * - is fulfilled if value is not a promise, or 401 * - if value is a promise, will fulfill with its value, or reject 402 * with its reason. 403 */ 404 // 该方法传递了value参数(用于闭包访问),内部调用了then方法,只传递了onFulfilled回调 405 // value值可以是立即数也是是promise对象 406 // 当调用yield方法的originalPromise被rejected,返回的newPromise对象也会因为同样的reason被rejected 407 // 而当originalPromise被resolved时,要分为两种情况: 408 // 1. 当value为立即数,那么newPromise对象将被resolved,且被传递value值 409 // 2. 当value为promise对象,那么返回的newPromise的命运(最后状态)将由value的状态决定,且被传递promise对象 410 // resolved的value值,或者rejected的reason值 411 // 总结,清楚then方法就可以很容易看清,yield内部通过只传递了onFulfilled回调,这个是关键因素 412 // 来个例子: 413 // var defer = when.defer(); 414 // var defer2 = when.defer(); 415 416 // defer.promise.yield(defer2.promise).then(function (value) { 417 // console.log('value: ' + value); 418 // }, function (reason) { 419 // console.log('reason: ' + reason); 420 // }); 421 422 // defer.reject('hello'); 423 // // defer.resolve('hello'); 424 425 // defer2.resolve('world'); 426 // // defer2.reject('world'); 427 428 // 结果:当defer->resolve&&defer2->resolve,输出value: world 429 // 当defer->resolve&&defer2->rejected,输出reason: world 430 // 当defer->rejected(跟defer2无关),输出reason: hello 431 432 promisePrototype['yield'] = function(value) { 433 return this.then(function() { 434 return value; 435 }); 436 }; 437 438 /** 439 * Runs a side effect when this promise fulfills, without changing the 440 * fulfillment value. 441 * @param {function} onFulfilledSideEffect 442 * @returns {Promise} 443 */ 444 // 1. 当promise对象resolved时,onFulfilledSideEffect被执行,对于onFulfilledSideEffect的返回值 445 // 没有任何意义,会被无视原因时因为['yield'](this)这句,迫使后面的promise对象与当前promise对象关联 446 // 在一起,传入后面callback的值也是当前promise对象resovle的value,或者reject的reason,但是如果 447 // onFulfilledSideEffect抛出异常或者返回rejected的promise对象,那么将会触发之后promise对象 448 // 的onRejected回调,并传入异常信息 449 // 2. 当promise对象rejected时,onFulfilledSideEffect不会被执行,之后的promise对象的onRejected回调 450 // 会被触发,并被传入当前promise对象reject的reason 451 // 例如: 452 // var defer = when.defer(); 453 454 // defer.promise.tap(function (value) { 455 456 // return 'good'; 457 // }).then(function (value) { 458 // console.log('value: ' + value); // value: hello 459 // }, function (reason) { 460 // console.log('reason: ' + reason); 461 // }); 462 // defer.resolve('hello'); 463 // 总结:上述的输出并不会因为我return了good而改变接下来输出的value值 464 promisePrototype.tap = function(onFulfilledSideEffect) { 465 return this.then(onFulfilledSideEffect)['yield'](this); 466 }; 467 468 /** 469 * Assumes that this promise will fulfill with an array, and arranges 470 * for the onFulfilled to be called with the array as its argument list 471 * i.e. onFulfilled.apply(undefined, array). 472 * @param {function} onFulfilled function to receive spread arguments 473 * @return {Promise} 474 */ 475 promisePrototype.spread = function(onFulfilled) { 476 return this.then(function(array) { 477 // array may contain promises, so resolve its contents. 478 return all(array, function(array) { 479 return onFulfilled.apply(undef, array); 480 }); 481 }); 482 }; 483 484 /** 485 * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected) 486 * @deprecated 487 */ 488 // 即将被废弃,可用finally(ensure)代替 489 promisePrototype.always = function(onFulfilledOrRejected, onProgress) { 490 return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); 491 }; 492 493 /** 494 * Casts x to a trusted promise. If x is already a trusted promise, it is 495 * returned, otherwise a new trusted Promise which follows x is returned. 496 * @param {*} x 497 * @returns {Promise} 498 */ 499 function cast(x) { 500 return x instanceof Promise ? x : resolve(x); 501 } 502 503 /** 504 * Returns a resolved promise. The returned promise will be 505 * - fulfilled with promiseOrValue if it is a value, or 506 * - if promiseOrValue is a promise 507 * - fulfilled with promiseOrValue's value after it is fulfilled 508 * - rejected with promiseOrValue's reason after it is rejected 509 * In contract to cast(x), this always creates a new Promise 510 * @param {*} value 511 * @return {Promise} 512 */ 513 // 内部调用when.promise方法,创建一个状态为resolved的promise对象 514 // 值得注意的是这里的value可以是一个promise对象 515 // 像这样: 516 // var defer = when.defer(); 517 // when.resolve(defer.promise).then(function (val) { 518 // console.log(val); // hello 519 // }); 520 // defer.resolve('hello'); 521 function resolve(value) { 522 return promise(function(resolve) { 523 resolve(value); 524 }); 525 } 526 527 /** 528 * Returns a rejected promise for the supplied promiseOrValue. The returned 529 * promise will be rejected with: 530 * - promiseOrValue, if it is a value, or 531 * - if promiseOrValue is a promise 532 * - promiseOrValue's value after it is fulfilled 533 * - promiseOrValue's reason after it is rejected 534 * @param {*} promiseOrValue the rejected value of the returned {@link Promise} 535 * @return {Promise} rejected {@link Promise} 536 */ 537 // 看到这里,可能会疑惑为什么代码是这样的?而不是这样的: 538 // function reject(promiseOrValue) { 539 // return promise(function(resolve, reject) { 540 // reject(value); 541 // }); 542 // } 543 // 问题在与reject方法只能接受字符串reason,然后构造成RejectedPromise实例, 544 // 不想resolve方法那样能够接受promise对象 545 // 为了满足同样能将promise对象作为参数,利用when内部处理promiseOrValue 546 // 例如: 547 // var defer = when.defer(); 548 549 // when.reject(defer.promise).then(function (value) { 550 // console.log('value: ' + value); 551 // }, function (reason) { 552 // console.log('reason: ' + reason); // reason: bad/good 553 // }); 554 555 // // defer.reject('bad'); 556 // defer.resolve('good'); 557 // 无论你的promise最终resolve还是reject,最终都是执行onRejected回调。 558 // 这里有个巧妙的地方就是 559 // 当resolve的时候,会利用下面的new RejectedPromise(e)来生成RejectedPromise对象 560 // 传递给下promise对象的resolve接口,进而执行onRejected 561 // 当reject时,会自动生成RejectedPromise对象,下面的new RejectedPromise(e)并不会被调用 562 function reject(promiseOrValue) { 563 return when(promiseOrValue, function(e) { 564 return new RejectedPromise(e); 565 }); 566 } 567 568 /** 569 * Creates a {promise, resolver} pair, either or both of which 570 * may be given out safely to consumers. 571 * The resolver has resolve, reject, and progress. The promise 572 * has then plus extended promise API. 573 * 574 * @return {{ 575 * promise: Promise, 576 * resolve: function:Promise, 577 * reject: function:Promise, 578 * notify: function:Promise 579 * resolver: { 580 * resolve: function:Promise, 581 * reject: function:Promise, 582 * notify: function:Promise 583 * }}} 584 */ 585 // defer函数用来返回一个deferred对象 586 // 内部包含promise对象以及操纵promise对象状态的三个接口 587 // 所以说deferred对象会改变promise的状态,而promise(defer.promise)对象时不可以改变自身的状态, 588 // 这就相当于jQuery Deferred中所谓的“受限制的deferred对象” 589 function defer() { 590 // deferred表示即将返回给用户的deferred对象 591 // pending可以理解为deferred.promise的别名,简单高效 592 // resolved表示该deferred是否已经reject或者resolve了 593 var deferred, pending, resolved; 594 595 // Optimize object shape 596 // 包装一下 597 deferred = { 598 promise: undef, resolve: undef, reject: undef, notify: undef, 599 resolver: { resolve: undef, reject: undef, notify: undef } 600 }; 601 602 // 创建promise对象,将控制权交给makeDeferred函数 603 deferred.promise = pending = promise(makeDeferred); 604 605 return deferred; 606 607 // 给deferred对象添加三个控制promise对象的接口 608 function makeDeferred(resolvePending, rejectPending, notifyPending) { 609 deferred.resolve = deferred.resolver.resolve = function(value) { 610 // 对于已经resolved的情况 611 // 根据传递进来的value创建已经新的resolved的promise对象 612 // 可以说已经与当前的promise对象已经没关系了 613 if(resolved) { 614 return resolve(value); 615 } 616 resolved = true; 617 // 执行promise对象的resolve 618 resolvePending(value); 619 // 返回resolved的promise对象,保持链式,被传递的值resolve时的只 620 return pending; 621 }; 622 623 // reject同上 624 deferred.reject = deferred.resolver.reject = function(reason) { 625 if(resolved) { 626 return resolve(new RejectedPromise(reason)); 627 } 628 resolved = true; 629 rejectPending(reason); 630 return pending; 631 }; 632 633 deferred.notify = deferred.resolver.notify = function(update) { 634 notifyPending(update); 635 return update; 636 }; 637 } 638 } 639 640 /** 641 * Run a queue of functions as quickly as possible, passing 642 * value to each. 643 */ 644 // 简单的遍历队列,执行函数 645 function runHandlers(queue, value) { 646 for (var i = 0; i < queue.length; i++) { 647 queue[i](value); 648 } 649 } 650 651 /** 652 * Coerces x to a trusted Promise 653 * @param {*} x thing to coerce 654 * @returns {*} Guaranteed to return a trusted Promise. If x 655 * is trusted, returns x, otherwise, returns a new, trusted, already-resolved 656 * Promise whose resolution value is: 657 * * the resolution value of x if it's a foreign promise, or 658 * * x if it's a value 659 */ 660 // 将x转换为对应的可信任的promise对象 661 function coerce(self, x) { 662 if (x === self) { 663 return new RejectedPromise(new TypeError()); 664 } 665 666 // 已经是promise对象,直接返回 667 // 比如:promise的对象或者它的三个子类实例 668 if (x instanceof Promise) { 669 return x; 670 } 671 672 try { 673 var untrustedThen = x === Object(x) && x.then; 674 675 return typeof untrustedThen === 'function' 676 ? assimilate(untrustedThen, x) 677 : new FulfilledPromise(x); 678 } catch(e) { 679 return new RejectedPromise(e); 680 } 681 } 682 683 /** 684 * Safely assimilates a foreign thenable by wrapping it in a trusted promise 685 * @param {function} untrustedThen x's then() method 686 * @param {object|function} x thenable 687 * @returns {Promise} 688 */ 689 // 将x为obj且带有then的函数进行封装并传递resolve和reject接口 690 // 返回promise对象 691 function assimilate(untrustedThen, x) { 692 return promise(function (resolve, reject) { 693 fcall(untrustedThen, x, resolve, reject); 694 }); 695 } 696 697 // 对Promise的原型继承(原生方法优先) 698 makePromisePrototype = Object.create || 699 function(o) { 700 function PromisePrototype() {} 701 PromisePrototype.prototype = o; 702 return new PromisePrototype(); 703 }; 704 705 /** 706 * Creates a fulfilled, local promise as a proxy for a value 707 * NOTE: must never be exposed 708 * @private 709 * @param {*} value fulfillment value 710 * @returns {Promise} 711 */ 712 // FulfilledPromise用于,当deferred.relove(value)时,对value的封装 713 function FulfilledPromise(value) { 714 this.value = value; 715 } 716 717 // 原型继承 718 FulfilledPromise.prototype = makePromisePrototype(promisePrototype); 719 720 // 返回promise的状态 721 FulfilledPromise.prototype.inspect = function() { 722 return toFulfilledState(this.value); 723 }; 724 725 FulfilledPromise.prototype._when = function(resolve, _, onFulfilled) { 726 // 这里的resolve适用于控制下一个关联的promise对象的 727 // 并且onFulfilled会被传递reslove(value)中的value值 728 // 如果onFulfilled有返回值,那么返回值会传递给下一个promise对象的回调函数 729 // 另外onFulfilled也可以不是对象,那么将此时的value传递给下一个promise对象的回调函数 730 // 对于用户自定义的函数onFulfilled采用try catch 731 try { 732 resolve(typeof onFulfilled === 'function' ? onFulfilled(this.value) : this.value); 733 } catch(e) { 734 resolve(new RejectedPromise(e)); 735 } 736 }; 737 738 /** 739 * Creates a rejected, local promise as a proxy for a value 740 * NOTE: must never be exposed 741 * @private 742 * @param {*} reason rejection reason 743 * @returns {Promise} 744 */ 745 // RejectedPromise用于,当deferred.reject(value)时,对value的封装 746 function RejectedPromise(reason) { 747 this.value = reason; 748 } 749 750 RejectedPromise.prototype = makePromisePrototype(promisePrototype); 751 752 RejectedPromise.prototype.inspect = function() { 753 return toRejectedState(this.value); 754 }; 755 756 RejectedPromise.prototype._when = function(resolve, _, __, onRejected) { 757 // 这里值得注意的是在onRejected不存在时,会将this对象作为一下promise对象的回调函数 758 // 保证RejectedPromise对象传递给下一个onRejected回调 759 // 而且注意这里也是用的resolve函数,而不是想像中的reject,所以在进行then方法的 760 // 链式调用下,如果一个promise对象resolved或rejected,它下一个promise对象会执行onFulfilled 761 // 除非你当时返回的一个rejected对象 762 try { 763 resolve(typeof onRejected === 'function' ? onRejected(this.value) : this); 764 } catch(e) { 765 resolve(new RejectedPromise(e)); 766 } 767 }; 768 769 /** 770 * Create a progress promise with the supplied update. 771 * @private 772 * @param {*} value progress update value 773 * @return {Promise} progress promise 774 */ 775 // ProgressingPromise用于,当deferred.notify(value)时,对value的封装 776 function ProgressingPromise(value) { 777 this.value = value; 778 } 779 780 ProgressingPromise.prototype = makePromisePrototype(promisePrototype); 781 782 ProgressingPromise.prototype._when = function(_, notify, f, r, u) { 783 try { 784 notify(typeof u === 'function' ? u(this.value) : this.value); 785 } catch(e) { 786 notify(e); 787 } 788 }; 789 790 /** 791 * Update a PromiseStatus monitor object with the outcome 792 * of the supplied value promise. 793 * @param {Promise} value 794 * @param {PromiseStatus} status 795 */ 796 function updateStatus(value, status) { 797 value.then(statusFulfilled, statusRejected); 798 799 function statusFulfilled() { status.fulfilled(); } 800 function statusRejected(r) { status.rejected(r); } 801 } 802 803 /** 804 * Determines if x is promise-like, i.e. a thenable object 805 * NOTE: Will return true for *any thenable object*, and isn't truly 806 * safe, since it may attempt to access the `then` property of x (i.e. 807 * clever/malicious getters may do weird things) 808 * @param {*} x anything 809 * @returns {boolean} true if x is promise-like 810 */ 811 // 判断一个对象是否like promise对象,很简单,即判断是否有then方法 812 function isPromiseLike(x) { 813 return x && typeof x.then === 'function'; 814 } 815 816 /** 817 * Initiates a competitive race, returning a promise that will resolve when 818 * howMany of the supplied promisesOrValues have resolved, or will reject when 819 * it becomes impossible for howMany to resolve, for example, when 820 * (promisesOrValues.length - howMany) + 1 input promises reject. 821 * 822 * @param {Array} promisesOrValues array of anything, may contain a mix 823 * of promises and values 824 * @param howMany {number} number of promisesOrValues to resolve 825 * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() 826 * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() 827 * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() 828 * @returns {Promise} promise that will resolve to an array of howMany values that 829 * resolved first, or will reject with an array of 830 * (promisesOrValues.length - howMany) + 1 rejection reasons. 831 */ 832 // some是用来解决5个promise对象当有3个resolve时,就去执行onFulfilled 833 // 如果超过3个reject时,就去执行onRejected 834 function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) { 835 836 // 注意:之前就有说过when方法时可以传递promisesOrValues数组的 837 return when(promisesOrValues, function(promisesOrValues) { 838 839 return promise(resolveSome).then(onFulfilled, onRejected, onProgress); 840 841 function resolveSome(resolve, reject, notify) { 842 var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i; 843 844 len = promisesOrValues.length >>> 0; 845 // resolve的条件 846 toResolve = Math.max(0, Math.min(howMany, len)); 847 values = []; 848 // reject的条件 849 toReject = (len - toResolve) + 1; 850 reasons = []; 851 852 // No items in the input, resolve immediately 853 // 空数组,直接resolve 854 if (!toResolve) { 855 resolve(values); 856 857 } else { 858 rejectOne = function(reason) { 859 // 保存reject的元素的reason信息 860 reasons.push(reason); 861 // 达到reject条件时 862 // 重置fulfillOne和rejectOne函数,不再保存接下来的数据 863 // 并reject返回的新创建的promise对象,以便执行onRejected回调 864 if(!--toReject) { 865 fulfillOne = rejectOne = identity; 866 reject(reasons); 867 } 868 }; 869 870 fulfillOne = function(val) { 871 // This orders the values based on promise resolution order 872 // 保存resolve的元素的reason信息,顺序取决于各个promise对象的resolve的先后顺序 873 // 接下来与rejectOne差不多 874 values.push(val); 875 if (!--toResolve) { 876 fulfillOne = rejectOne = identity; 877 resolve(values); 878 } 879 }; 880 // 遍历promisesOrValues数组 881 for(i = 0; i < len; ++i) { 882 if(i in promisesOrValues) { 883 when(promisesOrValues[i], fulfiller, rejecter, notify); 884 } 885 } 886 } 887 888 function rejecter(reason) { 889 rejectOne(reason); 890 } 891 892 function fulfiller(val) { 893 fulfillOne(val); 894 } 895 } 896 }); 897 } 898 899 /** 900 * Initiates a competitive race, returning a promise that will resolve when 901 * any one of the supplied promisesOrValues has resolved or will reject when 902 * *all* promisesOrValues have rejected. 903 * 904 * @param {Array|Promise} promisesOrValues array of anything, may contain a mix 905 * of {@link Promise}s and values 906 * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() 907 * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() 908 * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() 909 * @returns {Promise} promise that will resolve to the value that resolved first, or 910 * will reject with an array of all rejected inputs. 911 */ 912 // promisesOrValues数组中一个元素resolve那么执行onFulfilled,否则执行onRejected 913 // 内部调用some函数,将参数howMany置为1 914 function any(promisesOrValues, onFulfilled, onRejected, onProgress) { 915 916 function unwrapSingleResult(val) { 917 return onFulfilled ? onFulfilled(val[0]) : val[0]; 918 } 919 920 return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress); 921 } 922 923 /** 924 * Return a promise that will resolve only once all the supplied promisesOrValues 925 * have resolved. The resolution value of the returned promise will be an array 926 * containing the resolution values of each of the promisesOrValues. 927 * @memberOf when 928 * 929 * @param {Array|Promise} promisesOrValues array of anything, may contain a mix 930 * of {@link Promise}s and values 931 * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() 932 * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() 933 * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() 934 * @returns {Promise} 935 */ 936 // 与when.join功能几乎一样,就是传递参数的区别了,相见when.join 937 function all(promisesOrValues, onFulfilled, onRejected, onProgress) { 938 return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress); 939 } 940 941 /** 942 * Joins multiple promises into a single returned promise. 943 * @return {Promise} a promise that will fulfill when *all* the input promises 944 * have fulfilled, or will reject when *any one* of the input promises rejects. 945 */ 946 // when.join与when.map很想,都是调用_map,只不过它传递的时一个一个的promiseOrValue, 947 // 内部通过arguments伪数组传递给_map 948 // 而且指定函数为identity(返回每个resolve的value) 949 function join(/* ...promises */) { 950 return _map(arguments, identity); 951 } 952 953 /** 954 * Settles all input promises such that they are guaranteed not to 955 * be pending once the returned promise fulfills. The returned promise 956 * will always fulfill, except in the case where `array` is a promise 957 * that rejects. 958 * @param {Array|Promise} array or promise for array of promises to settle 959 * @returns {Promise} promise that always fulfills with an array of 960 * outcome snapshots for each input promise. 961 */ 962 // 遍历promiseOrValue数组,返回的新promise对象一定会resolve,除非array本身就是rejected的promise对象 963 // 且不会因为其中一个promise对象reject,而导致返回的新promise对象reject,而只会记录reject state的信息 964 // 这与when.all方法时不同的 965 // 可以看见内部调用了toFulfilledState和toRejectedState作为回调 966 // 那么返回的promise对象在onFulfilled将得到数组所有promiseOrValue的state信息 967 function settle(array) { 968 return _map(array, toFulfilledState, toRejectedState); 969 } 970 971 /** 972 * Promise-aware array map function, similar to `Array.prototype.map()`, 973 * but input array may contain promises or values. 974 * @param {Array|Promise} array array of anything, may contain promises and values 975 * @param {function} mapFunc map function which may return a promise or value 976 * @returns {Promise} promise that will fulfill with an array of mapped values 977 * or reject if any input promise rejects. 978 */ 979 // 遍历promiseOrValue数组,如果数组每个元素都resolve,那么会将每个元素在调用mapFunc时的返回值 980 // 保存在一个数组内,传递给返回的新的promise对象的onFulfilled方法,但是,如果有一个元素reject, 981 // 那么返回的那个promise对象的onRejected被调用,并接受这个元素的reason 982 // 如下: 983 // when.map([defer.promise, defer2.promise, 'three'], function (value) { 984 // return value; 985 // }).then(function (value) { 986 // console.log(value); // [ 'first', 'second', 'three' ] 987 // }, function (reason) { 988 // console.log(reason); 989 // }); 990 // defer.resolve('first'); 991 // defer2.resolve('second'); 992 function map(array, mapFunc) { 993 return _map(array, mapFunc); 994 } 995 996 /** 997 * Internal map that allows a fallback to handle rejections 998 * @param {Array|Promise} array array of anything, may contain promises and values 999 * @param {function} mapFunc map function which may return a promise or value 1000 * @param {function?} fallback function to handle rejected promises 1001 * @returns {Promise} promise that will fulfill with an array of mapped values 1002 * or reject if any input promise rejects. 1003 */ 1004 function _map(array, mapFunc, fallback) { 1005 // 这里array是一个promiseOrValue数组 1006 return when(array, function(array) { 1007 // 返回新的promise对象 1008 return new Promise(resolveMap); 1009 1010 function resolveMap(resolve, reject, notify) { 1011 var results, len, toResolve, i; 1012 1013 // Since we know the resulting length, we can preallocate the results 1014 // array to avoid array expansions. 1015 toResolve = len = array.length >>> 0; 1016 results = []; 1017 // 空数组直接返回 1018 if(!toResolve) { 1019 resolve(results); 1020 return; 1021 } 1022 1023 // Since mapFunc may be async, get all invocations of it into flight 1024 // 遍历数组内的promiseOrValue 1025 for(i = 0; i < len; i++) { 1026 // 数组元素验证,确保元素在数组内(数组也可以是伪数组) 1027 if(i in array) { 1028 1029 resolveOne(array[i], i); 1030 } else { 1031 --toResolve; 1032 } 1033 } 1034 1035 function resolveOne(item, i) { 1036 // 通过调用when方法将mapFunc(用户定义)函数的返回值存在results里, 1037 // 等最后toResolve为0时,一起传递给返回的新promise对象 1038 // 如果其中一个promise对象reject,那么reject返回的新promise对象 1039 // 返回值将是rejected的拿个promise对象的reason 1040 when(item, mapFunc, fallback).then(function(mapped) { 1041 // 保存每个promise对象的结果值 1042 results[i] = mapped; 1043 // 当所有promise对象都处理完了,resolve返回的新promise对象 1044 // 传递results数组 1045 if(!--toResolve) { 1046 resolve(results); 1047 } 1048 }, reject, notify); 1049 } 1050 } 1051 }); 1052 } 1053 1054 /** 1055 * Traditional reduce function, similar to `Array.prototype.reduce()`, but 1056 * input may contain promises and/or values, and reduceFunc 1057 * may return either a value or a promise, *and* initialValue may 1058 * be a promise for the starting value. 1059 * 1060 * @param {Array|Promise} promise array or promise for an array of anything, 1061 * may contain a mix of promises and values. 1062 * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total), 1063 * where total is the total number of items being reduced, and will be the same 1064 * in each call to reduceFunc. 1065 * @returns {Promise} that will resolve to the final reduced value 1066 */ 1067 function reduce(promise, reduceFunc /*, initialValue */) { 1068 var args = fcall(slice, arguments, 1); 1069 1070 return when(promise, function(array) { 1071 var total; 1072 1073 total = array.length; 1074 1075 // Wrap the supplied reduceFunc with one that handles promises and then 1076 // delegates to the supplied. 1077 args[0] = function (current, val, i) { 1078 return when(current, function (c) { 1079 return when(val, function (value) { 1080 return reduceFunc(c, value, i, total); 1081 }); 1082 }); 1083 }; 1084 1085 return reduceArray.apply(array, args); 1086 }); 1087 } 1088 1089 // Snapshot states 1090 1091 /** 1092 * Creates a fulfilled state snapshot 1093 * @private 1094 * @param {*} x any value 1095 * @returns {{state:'fulfilled',value:*}} 1096 */ 1097 function toFulfilledState(x) { 1098 return { state: 'fulfilled', value: x }; 1099 } 1100 1101 /** 1102 * Creates a rejected state snapshot 1103 * @private 1104 * @param {*} x any reason 1105 * @returns {{state:'rejected',reason:*}} 1106 */ 1107 function toRejectedState(x) { 1108 return { state: 'rejected', reason: x }; 1109 } 1110 1111 /** 1112 * Creates a pending state snapshot 1113 * @private 1114 * @returns {{state:'pending'}} 1115 */ 1116 function toPendingState() { 1117 return { state: 'pending' }; 1118 } 1119 1120 // 1121 // Internals, utilities, etc. 1122 // 1123 1124 var promisePrototype, makePromisePrototype, reduceArray, slice, fcall, nextTick, handlerQueue, 1125 funcProto, call, arrayProto, monitorApi, 1126 capturedSetTimeout, cjsRequire, MutationObs, undef; 1127 1128 cjsRequire = require; 1129 1130 // 1131 // Shared handler queue processing 1132 // 1133 // Credit to Twisol (https://github.com/Twisol) for suggesting 1134 // this type of extensible queue + trampoline approach for 1135 // next-tick conflation. 1136 // task队列 1137 handlerQueue = []; 1138 1139 /** 1140 * Enqueue a task. If the queue is not currently scheduled to be 1141 * drained, schedule it. 1142 * @param {function} task 1143 */ 1144 // 入队列,这里的进行了条件判断 1145 // 原因在于在异步情况下可能出现很多次enqueue调用,那么我们只对第一次入队调用nextTick 1146 // 下次时间周期自然会都被调用到 1147 function enqueue(task) { 1148 if(handlerQueue.push(task) === 1) { 1149 nextTick(drainQueue); 1150 } 1151 } 1152 1153 /** 1154 * Drain the handler queue entirely, being careful to allow the 1155 * queue to be extended while it is being processed, and to continue 1156 * processing until it is truly empty. 1157 */ 1158 // 出队列, 执行回调 1159 function drainQueue() { 1160 runHandlers(handlerQueue); 1161 handlerQueue = []; 1162 } 1163 1164 // Allow attaching the monitor to when() if env has no console 1165 monitorApi = typeof console !== 'undefined' ? console : when; 1166 1167 // Sniff "best" async scheduling option 1168 // Prefer process.nextTick or MutationObserver, then check for 1169 // vertx and finally fall back to setTimeout 1170 /*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/ 1171 // 以下是根据宿主环境采用不同的方式到达异步 1172 // 优先是nodejs的process.nextTick 1173 // 然后是MutationObserver 1174 // 最后是setTimeout 1175 // 这里异步的好处在于什么?为什么在reslove或者reject后,没有立即执行,而是加入队列, 1176 // 这是因为中途的task还有可能加入,在下一个时间周期统一处理,会很方便,提高性能,而且这样充分利用 1177 // javascript的单线程异步的特性,不会带来任何代码的阻塞问题 1178 if (typeof process === 'object' && process.nextTick) { 1179 nextTick = process.nextTick; 1180 } else if(MutationObs = 1181 (typeof MutationObserver === 'function' && MutationObserver) || 1182 (typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) { 1183 nextTick = (function(document, MutationObserver, drainQueue) { 1184 var el = document.createElement('div'); 1185 new MutationObserver(drainQueue).observe(el, { attributes: true }); 1186 1187 return function() { 1188 el.setAttribute('x', 'x'); 1189 }; 1190 }(document, MutationObs, drainQueue)); 1191 } else { 1192 try { 1193 // vert.x 1.x || 2.x 1194 nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext; 1195 } catch(ignore) { 1196 // capture setTimeout to avoid being caught by fake timers 1197 // used in time based tests 1198 capturedSetTimeout = setTimeout; 1199 nextTick = function(t) { capturedSetTimeout(t, 0); }; 1200 } 1201 } 1202 1203 // 1204 // Capture/polyfill function and array utils 1205 // 1206 1207 // Safe function calls 1208 funcProto = Function.prototype; 1209 call = funcProto.call; 1210 // 这里fcal的组合方式很有意思 1211 // 看下兼容代码就能明白了 1212 fcall = funcProto.bind 1213 ? call.bind(call) 1214 : function(f, context) { 1215 return f.apply(context, slice.call(arguments, 2)); 1216 }; 1217 1218 // Safe array ops 1219 arrayProto = []; 1220 slice = arrayProto.slice; 1221 1222 // ES5 reduce implementation if native not available 1223 // See: http://es5.github.com/#x15.4.4.21 as there are many 1224 // specifics and edge cases. ES5 dictates that reduce.length === 1 1225 // This implementation deviates from ES5 spec in the following ways: 1226 // 1. It does not check if reduceFunc is a Callable 1227 // 对[].reduce的兼容性处理 1228 reduceArray = arrayProto.reduce || 1229 function(reduceFunc /*, initialValue */) { 1230 /*jshint maxcomplexity: 7*/ 1231 var arr, args, reduced, len, i; 1232 1233 i = 0; 1234 arr = Object(this); 1235 len = arr.length >>> 0; 1236 args = arguments; 1237 1238 // If no initialValue, use first item of array (we know length !== 0 here) 1239 // and adjust i to start at second item 1240 if(args.length <= 1) { 1241 // Skip to the first real element in the array 1242 for(;;) { 1243 if(i in arr) { 1244 reduced = arr[i++]; 1245 break; 1246 } 1247 1248 // If we reached the end of the array without finding any real 1249 // elements, it's a TypeError 1250 if(++i >= len) { 1251 throw new TypeError(); 1252 } 1253 } 1254 } else { 1255 // If initialValue provided, use it 1256 reduced = args[1]; 1257 } 1258 1259 // Do the actual reduce 1260 for(;i < len; ++i) { 1261 if(i in arr) { 1262 reduced = reduceFunc(reduced, arr[i], i, arr); 1263 } 1264 } 1265 1266 return reduced; 1267 }; 1268 1269 function identity(x) { 1270 return x; 1271 } 1272 1273 function crash(fatalError) { 1274 if(typeof monitorApi.reportUnhandled === 'function') { 1275 monitorApi.reportUnhandled(); 1276 } else { 1277 enqueue(function() { 1278 throw fatalError; 1279 }); 1280 } 1281 1282 throw fatalError; 1283 } 1284 1285 return when; 1286 }); 1287 })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
晚安~~