現在,用回調處理一些復雜的邏輯,顯得代碼臃腫,難於閱讀,特別是異步,嵌套。
解決這樣的問題,可以是之前所說的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); });
晚安~~
