【原创】when.js2.7.1源码解析
2014-01-06 22:08
381 查看
现在,用回调处理一些复杂的逻辑,显得代码臃肿,难于阅读,特别是异步,嵌套。
解决这样的问题,可以是之前所说的Backbone.Events的pubsub,或者是今天要说的when.js所实现的promise。
在前端,jQuery的ajax全面改写就是为了引入promise这一套,为了使代码更流畅,更易于维护,事实上更容易实现复杂的需求。
jQuery Deferred所实现的promise并不是那么的规范,功能也并不能么全,在前端可以很方便的使用就是了,那么在后端(nodejs),我推荐
使用when.js,它的接口清晰,功能强大,架构更是很精妙,并且它在实现了完整的Promise A+后,又添加了好多扩展功能,使得在实际应用中,
能够很方便的写出优秀的代码。
所以对于这样强大的代码,当然是要去读一遍,学学作者的架构思路,花了几天时间阅读,对源代码进行了中文注释讲解(其中有放一些例子),
就贴在下面了,可能会有点长(看源代码都需要耐心嘛),如果有错误还望指证出来,多谢啦~
晚安~~
解决这样的问题,可以是之前所说的Backbone.Events的pubsub,或者是今天要说的when.js所实现的promise。
在前端,jQuery的ajax全面改写就是为了引入promise这一套,为了使代码更流畅,更易于维护,事实上更容易实现复杂的需求。
jQuery Deferred所实现的promise并不是那么的规范,功能也并不能么全,在前端可以很方便的使用就是了,那么在后端(nodejs),我推荐
使用when.js,它的接口清晰,功能强大,架构更是很精妙,并且它在实现了完整的Promise A+后,又添加了好多扩展功能,使得在实际应用中,
能够很方便的写出优秀的代码。
所以对于这样强大的代码,当然是要去读一遍,学学作者的架构思路,花了几天时间阅读,对源代码进行了中文注释讲解(其中有放一些例子),
就贴在下面了,可能会有点长(看源代码都需要耐心嘛),如果有错误还望指证出来,多谢啦~
/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * A lightweight CommonJS Promises/A and when() implementation * when is part of the cujo.js family of libraries (http://cujojs.com/) * * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author Brian Cavalier * @author John Hann * @version 2.7.1 */ // 首先是规范的兼容AMD(比如requirejs)和CMD(比如nodejs) (function(define) { 'use strict'; define(function (require) { // Public API // 接口很明确就是以下这些 // 首先promise对象拥有的三个状态:pending, resolved(fulfilled), rejected // 再然后需要理解promise对象和defer对象的关系 // 可以简单的理解为:defer对象内置了一个promise对象 // 它拥有两个接口resolve和reject来控制promise对象的最终的状态,从而进行异步操作的处理 when.promise = promise; // Create a pending promise(创建一个状态还是pending的promise对象) when.resolve = resolve; // Create a resolved promise (创建一个状态已经是resolved的promise对象) when.reject = reject; // Create a rejected promise(创建一个状态已经是resolved的promise对象) when.defer = defer; // Create a {promise, resolver} pair(创建一个defer对象) when.join = join; // Join 2 or more promises(解决多个promiseOrValue对象,与all想死) when.all = all; // Resolve a list of promises(等待所有promise都resolve,新的promise才resolve) when.map = map; // Array.map() for promises (类似数组的map) when.reduce = reduce; // Array.reduce() for promises(类似数组的reduce) when.settle = settle; // Settle a list of promises(处理promiseOrValue数组,返回state数组) when.any = any; // One-winner race(一个promiseOrValue resolve,新的promiseresolve) when.some = some; // Multi-winner race(some个promiseOrValue resolve,新的promiseresolve) when.isPromise = isPromiseLike; // DEPRECATED: use isPromiseLike when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable /** * Register an observer for a promise or immediate value. * * @param {*} promiseOrValue * @param {function?} [onFulfilled] callback to be called when promiseOrValue is * successfully fulfilled. If promiseOrValue is an immediate value, callback * will be invoked immediately. * @param {function?} [onRejected] callback to be called when promiseOrValue is * rejected. * @param {function?} [onProgress] callback to be called when progress updates * are issued for promiseOrValue. * @returns {Promise} a new {@link Promise} that will complete with the return * value of callback or errback or the completion value of promiseOrValue if * callback and/or errback is not supplied. */ // 官方的解释是:为一个promise对象或者立即数注册一个观察者 // 其实简单点就是 // 当promiseOrValue为resolved状态时,onRejected回调被调用 // 1. 当promiseOrValue被resolve时,onFulfilled回调被调用 // 2. 当promise为reject状态时,onRejected回调被调用 // 3. 当promise为notify状态时,onProgress回调被调用 // 注意: // 上述的第一点用的promiseOrValue,这里的value指的是立即数,立即数使得生成promise对象开始就是resolved状态 // 另外这里的promiseOrValue也可以是一个数组(即[promiseOrValue1, promiseOrValue2, ...]) function when(promiseOrValue, onFulfilled, onRejected, onProgress) { // Get a trusted promise for the input promiseOrValue, and then // register promise handlers // 首先这里先对promiseOrValue进行转换(cast方法),将其转变为promise对象 // 然后调用promise对象的then方法,并将用户提供的参数传递给then方法,等待被调用 // 最后返回then方法创建的新的promise对象,这样来维持链式 // 而且onFulfilled一般是函数,返回的值将作为形参传递给下一个onFulfilled, // 但如果不是函数那么onFulfilled的理应接受的参数将继续传递给下一个onFulfilled, // 也就是说可以继续这样调用: // when('hello', 'notFunction').then(function (v) { // console.log(v);// 这里的v就是hello // }); return cast(promiseOrValue).then(onFulfilled, onRejected, onProgress); } /** * Creates a new promise whose fate is determined by resolver. * @param {function} resolver function(resolve, reject, notify) * @returns {Promise} promise whose fate is determine by resolver */ // 创建一个promise对象,它的最终状态又resolver函数决定,为什么? // 因为resovler函数作为用户自定义函数会被传递三个形参,就是promise对象的三个内置改变状态的接口 // when.promise(function (reslove, reject, notify) { // resolve('xxx'); // fn1 被调用 // //reject('xxx'); // fn2 被调用 // //notify('xxx'); // fn3 被调用 // }).then(fn1, fn2, fn3); function promise(resolver) { // 实质是调用Promise构造函数 // 这里的PromiseStatus不是很清楚,好像是when/monitor下的文件,应该是辅助文件吧, // 可以先不用管 return new Promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus()); } /** * Trusted Promise constructor. A Promise created from this constructor is * a trusted when.js promise. Any other duck-typed promise is considered * untrusted. * @constructor * @returns {Promise} promise whose fate is determine by resolver * @name Promise */ // Promise构造器 // resolver上面已经说过,是一个函数 // status暂时先不管,跟程序主体关系不大 function Promise(resolver, status) { var self, value, consumers = []; self = this; this._status = status; this.inspect = inspect; this._when = _when; // Call the provider resolver to seal the promise's fate // 调用使用者提供的resolver函数,并将操作该promise对象“命运”的三个接口函数传递给resolver函数 // 利用try catch 捕获异常,毕竟resolver函数是使用者自定义的 // 如果异常将该promise对象reject // 其实这里是有些疑问的?如果该异常出现在promise对象resolve或者reject之后, // 这里catch里的reject就毫无用处了(毕竟promise的最终状态是不可以改变的) try { resolver(promiseResolve, promiseReject, promiseNotify); } catch(e) { promiseReject(e); } /** * Returns a snapshot of this promise's current status at the instant of call * @returns {{state:String}} */ // inspect函数用来查看当前promise对象的状态以及相关的值 function inspect() { //这里的value有三种情况: // pending时,为undefined // resolved时,是FulfilledPromise的实例 // rejected时,是FulfilledPromise的实例 // 所以在非空时这才有了对应的inspect方法 return value ? value.inspect() : toPendingState(); } /** * Private message delivery. Queues and delivers messages to * the promise's ultimate fulfillment value or rejection reason. * @private */ // 这里的_when私有函数起到至关重要的作用。 // 这里它利用consumers和enqueue数组存储经过封装后的callback,不同的是: // consumers里的callback是等待该promise对象resolve或者reject后执行 // enqueue里的callback是等待下个tick执行,或者说是延时执行(此时该promise对象已经resolved或者rejected了) // 另外巧妙通过闭包实现了对onFulfilled,onRejected,onProgress的访问, // 而无需像jQuery Deferrred那样通过创建维护三个队列存储callback function _when(resolve, notify, onFulfilled, onRejected, onProgress) { // 通过consumers参数判断该promise对象是否已经有了最终状态(即resolved或者rejected) // resloved(rejected)了,加入队列在下一个时间周期等待执行 // pending状态,存储起来在,等待适当的时候被执行(reslove或者reject的时候) consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); }); function deliver(p) { // 这里的p依然有三种值 // 1. 处于pending状态的promise对象 // 这种情苦发生在onFulfilled返回一个处于pending状态的promie对象, // 利用p._when关联之后的promise对象从而继续完成同步操作 // 如:(虽然异步,但是却是同步的写法,免去了callback的嵌套) // when.promise(function () { // var defer = when.defer(); // setTimout(function () { // defer.resolve('xx'); // }, 50) // }).then(function (val) { // console.log(val); // xx // }); // 2. FulfilledPromise对象 // 3. RejectedPromise对象 // 所以这里的p._when调用的方法出处各有不同 p._when(resolve, notify, onFulfilled, onRejected, onProgress); } } /** * Transition from pre-resolution state to post-resolution state, notifying * all listeners of the ultimate fulfillment or rejection * @param {*} val resolution value */ // 当前promise对象的resolve接口 function promiseResolve(val) { // val的值可以是有四种值 // 1. 立即数(经过coerce处理最终变为FulfilledPromise对象) // 2. promise对象 // 3. RejectedPromise对象(仅供内部传递,因为RejectedPromise是未暴露的函数类) // 3. FulfilledPromise对象(仅供内部传递) // 同样给出一个例子: // when.promise(function (resolve) { // // resolve('hello'); // 情况一立即数 // var defer = when.defer(); // setTimeout(function () { // 情况二promise对象,同样可以将setTimeout去掉试试 // defer.resolve('hello'); // // defer.reject('hello'); // }, 200); // resolve(defer.promise); // }).then(function (value) { // console.log(value); // hello // }); // consumers用来判断promise对象是否有了最终状态(即pending->resolved/rejected) // 因为根据Promises/A+规范规定,prmoise对象的最终状态是不可变的 // 也就是说resolve和reject只会被执行一次 if(!consumers) { return; } // 将consumers置为undefined表示promise对象已经resolve或者reject了 var queue = consumers; consumers = undef; // 将当前要执行的任务入队列,等待下一个时刻执行,将异步进行到底 enqueue(function () { // coerce进行val的转换 // 转换为promise对象或者promise的子类RejectedPromise/FulfilledPromise的实例 // 传递给value,value很重要,作为最终的值,之后回通过必包传递给一个关联回调 value = coerce(self, val); if(status) { updateStatus(value, status); } // 运行consumers里传递过来的函数队列 runHandlers(queue, value); }); } /** * Reject this promise with the supplied reason, which will be used verbatim. * @param {*} reason reason for the rejection */ // 当前promise对象的reject接口 // 实质还是利用resolve的接口,只不过是主动传递RejectedPromise的实例 function promiseReject(reason) { promiseResolve(new RejectedPromise(reason)); } /** * Issue a progress event, notifying all progress listeners * @param {*} update progress event payload to pass to all listeners */ // notify就是一个进度提示,这在做一些进度方面的组件是很有用户体验的,比如flash uploader // 显然既然是进度,那么首先promise对象是必须还处于pending状态,notify才会有效 // 所以consumers必须不为空 // 给个例子: // when.promise(function (resolve, reject, notify) { // var counter = 0; // var timer = setInterval(function () { // counter++; // notify(counter); // if (counter === 10) { // resolve('over'); // clearInterval(timer); // } // }, 1); // }).then(function (value) { // console.log(value); // }, undefined, function (update) { // console.log(update); // }); // 结果是 1 2 3 4 5 6 7 8 9 10 over function promiseNotify(update) { if(consumers) { var queue = consumers; enqueue(function () { runHandlers(queue, new ProgressingPromise(update)); }); } } } // 接下来是Promise的原型方法,最重要的就是then方法 promisePrototype = Promise.prototype; /** * Register handlers for this promise. * @param [onFulfilled] {Function} fulfillment handler * @param [onRejected] {Function} rejection handler * @param [onProgress] {Function} progress handler * @return {Promise} new Promise */ // then方法是Promises/A+的核心,也是链式的关键,用来注册三种回调 // 通过调用_when的私有方法能做到以下几点: // 1. 进行callback的注册 // 2. 创建新的promise对象(newPromise)并返回,继续链式下去 // 3. 将newPromise对象的决定权(即三个内置接口)交付给调用then方法的promise对象(即与之关联在一起) promisePrototype.then = function(onFulfilled, onRejected, onProgress) { var self = this; return new Promise(function(resolve, reject, notify) { self._when(resolve, notify, onFulfilled, onRejected, onProgress); }, this._status && this._status.observed()); }; /** * Register a rejection handler. Shortcut for .then(undefined, onRejected) * @param {function?} onRejected * @return {Promise} */ // 很明显内部调用了then方法,只传递了onRejected函数 // 其实相当于promise.then(undef, onRejected)的快捷键 promisePrototype['catch'] = promisePrototype.otherwise = function(onRejected) { return this.then(undef, onRejected); }; /** * Ensures that onFulfilledOrRejected will be called regardless of whether * this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT * receive the promises' value or reason. Any returned value will be disregarded. * onFulfilledOrRejected may throw or return a rejected promise to signal * an additional error. * @param {function} onFulfilledOrRejected handler to be called regardless of * fulfillment or rejection * @returns {Promise} */ // finally和ensure方法保证promise对象无论什么状态的情况下,最终都会执行onFulfilledOrRejected // 但是onFulfilledOrRejected是不带任何参数的 // 另外,finally(ensure)方法如果后面继续链式,添加then方法,最终执行是与该promise对象相关的,并且接受 // promise对象的resolve的value值和reject的reason值(与finally的返回值无关,除非onFulfilledOrRejected // 回调报出异常或者返回rejected的promise对象) // 举个例子: // var when = require('when'); // var defer = when.defer(); // defer.promise.finally(function () { // console.log(arguments); // {} // var defer2 = when.defer(); // defer2.reject('xxx'); // return defer2.promise; // }).then(function (value) { // console.log('value: ' + value); // }, function (reason) { // console.log('reason: ' + reason); // reason: xxx // }); // defer.resolve('hello'); promisePrototype['finally'] = promisePrototype.ensure = function(onFulfilledOrRejected) { // 这里利用yield(this),试图将接下来的newPromise对象的控制权交给当前的promise对象 return typeof onFulfilledOrRejected === 'function' ? this.then(injectHandler, injectHandler)['yield'](this) : this; function injectHandler() { // 这里是为了配合yield方法,试图想返回一个resolved的promise对象 // 但是onFulfilledOrRejected(),如果发生异常,或者返回rejectedpromise对象 // 将会使得结果与当前promise对象的状态无关了,就像上面代码没有输出hello一样 return resolve(onFulfilledOrRejected()); } }; /** * Terminate a promise chain by handling the ultimate fulfillment value or * rejection reason, and assuming responsibility for all errors. if an * error propagates out of handleResult or handleFatalError, it will be * rethrown to the host, resulting in a loud stack track on most platforms * and a crash on some. * @param {function?} handleResult * @param {function?} handleError * @returns {undefined} */ // done方法有两个作用: // 1. 结束链式 // 2. 异常处理 // 如下: // var when = require('when'); // var defer = when.defer(); // defer.promise.done(function () { // console.log(arguments) // }, function (value) { // var defer = when.defer(); // defer.reject(value) // return defer.promise(); // }); // defer.reject('world'); // 将会报出程序异常,结束程序执行 promisePrototype.done = function(handleResult, handleError) { this.then(handleResult, handleError)['catch'](crash); }; /** * Shortcut for .then(function() { return value; }) * @param {*} value * @return {Promise} a promise that: * - is fulfilled if value is not a promise, or * - if value is a promise, will fulfill with its value, or reject * with its reason. */ // 该方法传递了value参数(用于闭包访问),内部调用了then方法,只传递了onFulfilled回调 // value值可以是立即数也是是promise对象 // 当调用yield方法的originalPromise被rejected,返回的newPromise对象也会因为同样的reason被rejected // 而当originalPromise被resolved时,要分为两种情况: // 1. 当value为立即数,那么newPromise对象将被resolved,且被传递value值 // 2. 当value为promise对象,那么返回的newPromise的命运(最后状态)将由value的状态决定,且被传递promise对象 // resolved的value值,或者rejected的reason值 // 总结,清楚then方法就可以很容易看清,yield内部通过只传递了onFulfilled回调,这个是关键因素 // 来个例子: // var defer = when.defer(); // var defer2 = when.defer(); // defer.promise.yield(defer2.promise).then(function (value) { // console.log('value: ' + value); // }, function (reason) { // console.log('reason: ' + reason); // }); // defer.reject('hello'); // // defer.resolve('hello'); // defer2.resolve('world'); // // defer2.reject('world'); // 结果:当defer->resolve&&defer2->resolve,输出value: world // 当defer->resolve&&defer2->rejected,输出reason: world // 当defer->rejected(跟defer2无关),输出reason: hello promisePrototype['yield'] = function(value) { return this.then(function() { return value; }); }; /** * Runs a side effect when this promise fulfills, without changing the * fulfillment value. * @param {function} onFulfilledSideEffect * @returns {Promise} */ // 1. 当promise对象resolved时,onFulfilledSideEffect被执行,对于onFulfilledSideEffect的返回值 // 没有任何意义,会被无视原因时因为['yield'](this)这句,迫使后面的promise对象与当前promise对象关联 // 在一起,传入后面callback的值也是当前promise对象resovle的value,或者reject的reason,但是如果 // onFulfilledSideEffect抛出异常或者返回rejected的promise对象,那么将会触发之后promise对象 // 的onRejected回调,并传入异常信息 // 2. 当promise对象rejected时,onFulfilledSideEffect不会被执行,之后的promise对象的onRejected回调 // 会被触发,并被传入当前promise对象reject的reason // 例如: // var defer = when.defer(); // defer.promise.tap(function (value) { // return 'good'; // }).then(function (value) { // console.log('value: ' + value); // value: hello // }, function (reason) { // console.log('reason: ' + reason); // }); // defer.resolve('hello'); // 总结:上述的输出并不会因为我return了good而改变接下来输出的value值 promisePrototype.tap = function(onFulfilledSideEffect) { return this.then(onFulfilledSideEffect)['yield'](this); }; /** * Assumes that this promise will fulfill with an array, and arranges * for the onFulfilled to be called with the array as its argument list * i.e. onFulfilled.apply(undefined, array). * @param {function} onFulfilled function to receive spread arguments * @return {Promise} */ promisePrototype.spread = function(onFulfilled) { return this.then(function(array) { // array may contain promises, so resolve its contents. return all(array, function(array) { return onFulfilled.apply(undef, array); }); }); }; /** * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected) * @deprecated */ // 即将被废弃,可用finally(ensure)代替 promisePrototype.always = function(onFulfilledOrRejected, onProgress) { return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); }; /** * Casts x to a trusted promise. If x is already a trusted promise, it is * returned, otherwise a new trusted Promise which follows x is returned. * @param {*} x * @returns {Promise} */ function cast(x) { return x instanceof Promise ? x : resolve(x); } /** * Returns a resolved promise. The returned promise will be * - fulfilled with promiseOrValue if it is a value, or * - if promiseOrValue is a promise * - fulfilled with promiseOrValue's value after it is fulfilled * - rejected with promiseOrValue's reason after it is rejected * In contract to cast(x), this always creates a new Promise * @param {*} value * @return {Promise} */ // 内部调用when.promise方法,创建一个状态为resolved的promise对象 // 值得注意的是这里的value可以是一个promise对象 // 像这样: // var defer = when.defer(); // when.resolve(defer.promise).then(function (val) { // console.log(val); // hello // }); // defer.resolve('hello'); function resolve(value) { return promise(function(resolve) { resolve(value); }); } /** * Returns a rejected promise for the supplied promiseOrValue. The returned * promise will be rejected with: * - promiseOrValue, if it is a value, or * - if promiseOrValue is a promise * - promiseOrValue's value after it is fulfilled * - promiseOrValue's reason after it is rejected * @param {*} promiseOrValue the rejected value of the returned {@link Promise} * @return {Promise} rejected {@link Promise} */ // 看到这里,可能会疑惑为什么代码是这样的?而不是这样的: // function reject(promiseOrValue) { // return promise(function(resolve, reject) { // reject(value); // }); // } // 问题在与reject方法只能接受字符串reason,然后构造成RejectedPromise实例, // 不想resolve方法那样能够接受promise对象 // 为了满足同样能将promise对象作为参数,利用when内部处理promiseOrValue // 例如: // var defer = when.defer(); // when.reject(defer.promise).then(function (value) { // console.log('value: ' + value); // }, function (reason) { // console.log('reason: ' + reason); // reason: bad/good // }); // // defer.reject('bad'); // defer.resolve('good'); // 无论你的promise最终resolve还是reject,最终都是执行onRejected回调。 // 这里有个巧妙的地方就是 // 当resolve的时候,会利用下面的new RejectedPromise(e)来生成RejectedPromise对象 // 传递给下promise对象的resolve接口,进而执行onRejected // 当reject时,会自动生成RejectedPromise对象,下面的new RejectedPromise(e)并不会被调用 function reject(promiseOrValue) { return when(promiseOrValue, function(e) { return new RejectedPromise(e); }); } /** * Creates a {promise, resolver} pair, either or both of which * may be given out safely to consumers. * The resolver has resolve, reject, and progress. The promise * has then plus extended promise API. * * @return {{ * promise: Promise, * resolve: function:Promise, * reject: function:Promise, * notify: function:Promise * resolver: { * resolve: function:Promise, * reject: function:Promise, * notify: function:Promise * }}} */ // defer函数用来返回一个deferred对象 // 内部包含promise对象以及操纵promise对象状态的三个接口 // 所以说deferred对象会改变promise的状态,而promise(defer.promise)对象时不可以改变自身的状态, // 这就相当于jQuery Deferred中所谓的“受限制的deferred对象” function defer() { // deferred表示即将返回给用户的deferred对象 // pending可以理解为deferred.promise的别名,简单高效 // resolved表示该deferred是否已经reject或者resolve了 var deferred, pending, resolved; // Optimize object shape // 包装一下 deferred = { promise: undef, resolve: undef, reject: undef, notify: undef, resolver: { resolve: undef, reject: undef, notify: undef } }; // 创建promise对象,将控制权交给makeDeferred函数 deferred.promise = pending = promise(makeDeferred); return deferred; // 给deferred对象添加三个控制promise对象的接口 function makeDeferred(resolvePending, rejectPending, notifyPending) { deferred.resolve = deferred.resolver.resolve = function(value) { // 对于已经resolved的情况 // 根据传递进来的value创建已经新的resolved的promise对象 // 可以说已经与当前的promise对象已经没关系了 if(resolved) { return resolve(value); } resolved = true; // 执行promise对象的resolve resolvePending(value); // 返回resolved的promise对象,保持链式,被传递的值resolve时的只 return pending; }; // reject同上 deferred.reject = deferred.resolver.reject = function(reason) { if(resolved) { return resolve(new RejectedPromise(reason)); } resolved = true; rejectPending(reason); return pending; }; deferred.notify = deferred.resolver.notify = function(update) { notifyPending(update); return update; }; } } /** * Run a queue of functions as quickly as possible, passing * value to each. */ // 简单的遍历队列,执行函数 function runHandlers(queue, value) { for (var i = 0; i < queue.length; i++) { queue[i](value); } } /** * Coerces x to a trusted Promise * @param {*} x thing to coerce * @returns {*} Guaranteed to return a trusted Promise. If x * is trusted, returns x, otherwise, returns a new, trusted, already-resolved * Promise whose resolution value is: * * the resolution value of x if it's a foreign promise, or * * x if it's a value */ // 将x转换为对应的可信任的promise对象 function coerce(self, x) { if (x === self) { return new RejectedPromise(new TypeError()); } // 已经是promise对象,直接返回 // 比如:promise的对象或者它的三个子类实例 if (x instanceof Promise) { return x; } try { var untrustedThen = x === Object(x) && x.then; return typeof untrustedThen === 'function' ? assimilate(untrustedThen, x) : new FulfilledPromise(x); } catch(e) { return new RejectedPromise(e); } } /** * Safely assimilates a foreign thenable by wrapping it in a trusted promise * @param {function} untrustedThen x's then() method * @param {object|function} x thenable * @returns {Promise} */ // 将x为obj且带有then的函数进行封装并传递resolve和reject接口 // 返回promise对象 function assimilate(untrustedThen, x) { return promise(function (resolve, reject) { fcall(untrustedThen, x, resolve, reject); }); } // 对Promise的原型继承(原生方法优先) makePromisePrototype = Object.create || function(o) { function PromisePrototype() {} PromisePrototype.prototype = o; return new PromisePrototype(); }; /** * Creates a fulfilled, local promise as a proxy for a value * NOTE: must never be exposed * @private * @param {*} value fulfillment value * @returns {Promise} */ // FulfilledPromise用于,当deferred.relove(value)时,对value的封装 function FulfilledPromise(value) { this.value = value; } // 原型继承 FulfilledPromise.prototype = makePromisePrototype(promisePrototype); // 返回promise的状态 FulfilledPromise.prototype.inspect = function() { return toFulfilledState(this.value); }; FulfilledPromise.prototype._when = function(resolve, _, onFulfilled) { // 这里的resolve适用于控制下一个关联的promise对象的 // 并且onFulfilled会被传递reslove(value)中的value值 // 如果onFulfilled有返回值,那么返回值会传递给下一个promise对象的回调函数 // 另外onFulfilled也可以不是对象,那么将此时的value传递给下一个promise对象的回调函数 // 对于用户自定义的函数onFulfilled采用try catch try { resolve(typeof onFulfilled === 'function' ? onFulfilled(this.value) : this.value); } catch(e) { resolve(new RejectedPromise(e)); } }; /** * Creates a rejected, local promise as a proxy for a value * NOTE: must never be exposed * @private * @param {*} reason rejection reason * @returns {Promise} */ // RejectedPromise用于,当deferred.reject(value)时,对value的封装 function RejectedPromise(reason) { this.value = reason; } RejectedPromise.prototype = makePromisePrototype(promisePrototype); RejectedPromise.prototype.inspect = function() { return toRejectedState(this.value); }; RejectedPromise.prototype._when = function(resolve, _, __, onRejected) { // 这里值得注意的是在onRejected不存在时,会将this对象作为一下promise对象的回调函数 // 保证RejectedPromise对象传递给下一个onRejected回调 // 而且注意这里也是用的resolve函数,而不是想像中的reject,所以在进行then方法的 // 链式调用下,如果一个promise对象resolved或rejected,它下一个promise对象会执行onFulfilled // 除非你当时返回的一个rejected对象 try { resolve(typeof onRejected === 'function' ? onRejected(this.value) : this); } catch(e) { resolve(new RejectedPromise(e)); } }; /** * Create a progress promise with the supplied update. * @private * @param {*} value progress update value * @return {Promise} progress promise */ // ProgressingPromise用于,当deferred.notify(value)时,对value的封装 function ProgressingPromise(value) { this.value = value; } ProgressingPromise.prototype = makePromisePrototype(promisePrototype); ProgressingPromise.prototype._when = function(_, notify, f, r, u) { try { notify(typeof u === 'function' ? u(this.value) : this.value); } catch(e) { notify(e); } }; /** * Update a PromiseStatus monitor object with the outcome * of the supplied value promise. * @param {Promise} value * @param {PromiseStatus} status */ function updateStatus(value, status) { value.then(statusFulfilled, statusRejected); function statusFulfilled() { status.fulfilled(); } function statusRejected(r) { status.rejected(r); } } /** * Determines if x is promise-like, i.e. a thenable object * NOTE: Will return true for *any thenable object*, and isn't truly * safe, since it may attempt to access the `then` property of x (i.e. * clever/malicious getters may do weird things) * @param {*} x anything * @returns {boolean} true if x is promise-like */ // 判断一个对象是否like promise对象,很简单,即判断是否有then方法 function isPromiseLike(x) { return x && typeof x.then === 'function'; } /** * Initiates a competitive race, returning a promise that will resolve when * howMany of the supplied promisesOrValues have resolved, or will reject when * it becomes impossible for howMany to resolve, for example, when * (promisesOrValues.length - howMany) + 1 input promises reject. * * @param {Array} promisesOrValues array of anything, may contain a mix * of promises and values * @param howMany {number} number of promisesOrValues to resolve * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() * @returns {Promise} promise that will resolve to an array of howMany values that * resolved first, or will reject with an array of * (promisesOrValues.length - howMany) + 1 rejection reasons. */ // some是用来解决5个promise对象当有3个resolve时,就去执行onFulfilled // 如果超过3个reject时,就去执行onRejected function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) { // 注意:之前就有说过when方法时可以传递promisesOrValues数组的 return when(promisesOrValues, function(promisesOrValues) { return promise(resolveSome).then(onFulfilled, onRejected, onProgress); function resolveSome(resolve, reject, notify) { var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i; len = promisesOrValues.length >>> 0; // resolve的条件 toResolve = Math.max(0, Math.min(howMany, len)); values = []; // reject的条件 toReject = (len - toResolve) + 1; reasons = []; // No items in the input, resolve immediately // 空数组,直接resolve if (!toResolve) { resolve(values); } else { rejectOne = function(reason) { // 保存reject的元素的reason信息 reasons.push(reason); // 达到reject条件时 // 重置fulfillOne和rejectOne函数,不再保存接下来的数据 // 并reject返回的新创建的promise对象,以便执行onRejected回调 if(!--toReject) { fulfillOne = rejectOne = identity; reject(reasons); } }; fulfillOne = function(val) { // This orders the values based on promise resolution order // 保存resolve的元素的reason信息,顺序取决于各个promise对象的resolve的先后顺序 // 接下来与rejectOne差不多 values.push(val); if (!--toResolve) { fulfillOne = rejectOne = identity; resolve(values); } }; // 遍历promisesOrValues数组 for(i = 0; i < len; ++i) { if(i in promisesOrValues) { when(promisesOrValues[i], fulfiller, rejecter, notify); } } } function rejecter(reason) { rejectOne(reason); } function fulfiller(val) { fulfillOne(val); } } }); } /** * Initiates a competitive race, returning a promise that will resolve when * any one of the supplied promisesOrValues has resolved or will reject when * *all* promisesOrValues have rejected. * * @param {Array|Promise} promisesOrValues array of anything, may contain a mix * of {@link Promise}s and values * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() * @returns {Promise} promise that will resolve to the value that resolved first, or * will reject with an array of all rejected inputs. */ // promisesOrValues数组中一个元素resolve那么执行onFulfilled,否则执行onRejected // 内部调用some函数,将参数howMany置为1 function any(promisesOrValues, onFulfilled, onRejected, onProgress) { function unwrapSingleResult(val) { return onFulfilled ? onFulfilled(val[0]) : val[0]; } return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress); } /** * Return a promise that will resolve only once all the supplied promisesOrValues * have resolved. The resolution value of the returned promise will be an array * containing the resolution values of each of the promisesOrValues. * @memberOf when * * @param {Array|Promise} promisesOrValues array of anything, may contain a mix * of {@link Promise}s and values * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() * @returns {Promise} */ // 与when.join功能几乎一样,就是传递参数的区别了,相见when.join function all(promisesOrValues, onFulfilled, onRejected, onProgress) { return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress); } /** * Joins multiple promises into a single returned promise. * @return {Promise} a promise that will fulfill when *all* the input promises * have fulfilled, or will reject when *any one* of the input promises rejects. */ // when.join与when.map很想,都是调用_map,只不过它传递的时一个一个的promiseOrValue, // 内部通过arguments伪数组传递给_map // 而且指定函数为identity(返回每个resolve的value) function join(/* ...promises */) { return _map(arguments, identity); } /** * Settles all input promises such that they are guaranteed not to * be pending once the returned promise fulfills. The returned promise * will always fulfill, except in the case where `array` is a promise * that rejects. * @param {Array|Promise} array or promise for array of promises to settle * @returns {Promise} promise that always fulfills with an array of * outcome snapshots for each input promise. */ // 遍历promiseOrValue数组,返回的新promise对象一定会resolve,除非array本身就是rejected的promise对象 // 且不会因为其中一个promise对象reject,而导致返回的新promise对象reject,而只会记录reject state的信息 // 这与when.all方法时不同的 // 可以看见内部调用了toFulfilledState和toRejectedState作为回调 // 那么返回的promise对象在onFulfilled将得到数组所有promiseOrValue的state信息 function settle(array) { return _map(array, toFulfilledState, toRejectedState); } /** * Promise-aware array map function, similar to `Array.prototype.map()`, * but input array may contain promises or values. * @param {Array|Promise} array array of anything, may contain promises and values * @param {function} mapFunc map function which may return a promise or value * @returns {Promise} promise that will fulfill with an array of mapped values * or reject if any input promise rejects. */ // 遍历promiseOrValue数组,如果数组每个元素都resolve,那么会将每个元素在调用mapFunc时的返回值 // 保存在一个数组内,传递给返回的新的promise对象的onFulfilled方法,但是,如果有一个元素reject, // 那么返回的那个promise对象的onRejected被调用,并接受这个元素的reason // 如下: // when.map([defer.promise, defer2.promise, 'three'], function (value) { // return value; // }).then(function (value) { // console.log(value); // [ 'first', 'second', 'three' ] // }, function (reason) { // console.log(reason); // }); // defer.resolve('first'); // defer2.resolve('second'); function map(array, mapFunc) { return _map(array, mapFunc); } /** * Internal map that allows a fallback to handle rejections * @param {Array|Promise} array array of anything, may contain promises and values * @param {function} mapFunc map function which may return a promise or value * @param {function?} fallback function to handle rejected promises * @returns {Promise} promise that will fulfill with an array of mapped values * or reject if any input promise rejects. */ function _map(array, mapFunc, fallback) { // 这里array是一个promiseOrValue数组 return when(array, function(array) { // 返回新的promise对象 return new Promise(resolveMap); function resolveMap(resolve, reject, notify) { var results, len, toResolve, i; // Since we know the resulting length, we can preallocate the results // array to avoid array expansions. toResolve = len = array.length >>> 0; results = []; // 空数组直接返回 if(!toResolve) { resolve(results); return; } // Since mapFunc may be async, get all invocations of it into flight // 遍历数组内的promiseOrValue for(i = 0; i < len; i++) { // 数组元素验证,确保元素在数组内(数组也可以是伪数组) if(i in array) { resolveOne(array[i], i); } else { --toResolve; } } function resolveOne(item, i) { // 通过调用when方法将mapFunc(用户定义)函数的返回值存在results里, // 等最后toResolve为0时,一起传递给返回的新promise对象 // 如果其中一个promise对象reject,那么reject返回的新promise对象 // 返回值将是rejected的拿个promise对象的reason when(item, mapFunc, fallback).then(function(mapped) { // 保存每个promise对象的结果值 results[i] = mapped; // 当所有promise对象都处理完了,resolve返回的新promise对象 // 传递results数组 if(!--toResolve) { resolve(results); } }, reject, notify); } } }); } /** * Traditional reduce function, similar to `Array.prototype.reduce()`, but * input may contain promises and/or values, and reduceFunc * may return either a value or a promise, *and* initialValue may * be a promise for the starting value. * * @param {Array|Promise} promise array or promise for an array of anything, * may contain a mix of promises and values. * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total), * where total is the total number of items being reduced, and will be the same * in each call to reduceFunc. * @returns {Promise} that will resolve to the final reduced value */ function reduce(promise, reduceFunc /*, initialValue */) { var args = fcall(slice, arguments, 1); return when(promise, function(array) { var total; total = array.length; // Wrap the supplied reduceFunc with one that handles promises and then // delegates to the supplied. args[0] = function (current, val, i) { return when(current, function (c) { return when(val, function (value) { return reduceFunc(c, value, i, total); }); }); }; return reduceArray.apply(array, args); }); } // Snapshot states /** * Creates a fulfilled state snapshot * @private * @param {*} x any value * @returns {{state:'fulfilled',value:*}} */ function toFulfilledState(x) { return { state: 'fulfilled', value: x }; } /** * Creates a rejected state snapshot * @private * @param {*} x any reason * @returns {{state:'rejected',reason:*}} */ function toRejectedState(x) { return { state: 'rejected', reason: x }; } /** * Creates a pending state snapshot * @private * @returns {{state:'pending'}} */ function toPendingState() { return { state: 'pending' }; } // // Internals, utilities, etc. // var promisePrototype, makePromisePrototype, reduceArray, slice, fcall, nextTick, handlerQueue, funcProto, call, arrayProto, monitorApi, capturedSetTimeout, cjsRequire, MutationObs, undef; cjsRequire = require; // // Shared handler queue processing // // Credit to Twisol (https://github.com/Twisol) for suggesting // this type of extensible queue + trampoline approach for // next-tick conflation. // task队列 handlerQueue = []; /** * Enqueue a task. If the queue is not currently scheduled to be * drained, schedule it. * @param {function} task */ // 入队列,这里的进行了条件判断 // 原因在于在异步情况下可能出现很多次enqueue调用,那么我们只对第一次入队调用nextTick // 下次时间周期自然会都被调用到 function enqueue(task) { if(handlerQueue.push(task) === 1) { nextTick(drainQueue); } } /** * Drain the handler queue entirely, being careful to allow the * queue to be extended while it is being processed, and to continue * processing until it is truly empty. */ // 出队列, 执行回调 function drainQueue() { runHandlers(handlerQueue); handlerQueue = []; } // Allow attaching the monitor to when() if env has no console monitorApi = typeof console !== 'undefined' ? console : when; // Sniff "best" async scheduling option // Prefer process.nextTick or MutationObserver, then check for // vertx and finally fall back to setTimeout /*global process,document,setTimeout,MutationObserver,WebKitMutationObserver*/ // 以下是根据宿主环境采用不同的方式到达异步 // 优先是nodejs的process.nextTick // 然后是MutationObserver // 最后是setTimeout // 这里异步的好处在于什么?为什么在reslove或者reject后,没有立即执行,而是加入队列, // 这是因为中途的task还有可能加入,在下一个时间周期统一处理,会很方便,提高性能,而且这样充分利用 // javascript的单线程异步的特性,不会带来任何代码的阻塞问题 if (typeof process === 'object' && process.nextTick) { nextTick = process.nextTick; } else if(MutationObs = (typeof MutationObserver === 'function' && MutationObserver) || (typeof WebKitMutationObserver === 'function' && WebKitMutationObserver)) { nextTick = (function(document, MutationObserver, drainQueue) { var el = document.createElement('div'); new MutationObserver(drainQueue).observe(el, { attributes: true }); return function() { el.setAttribute('x', 'x'); }; }(document, MutationObs, drainQueue)); } else { try { // vert.x 1.x || 2.x nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext; } catch(ignore) { // capture setTimeout to avoid being caught by fake timers // used in time based tests capturedSetTimeout = setTimeout; nextTick = function(t) { capturedSetTimeout(t, 0); }; } } // // Capture/polyfill function and array utils // // Safe function calls funcProto = Function.prototype; call = funcProto.call; // 这里fcal的组合方式很有意思 // 看下兼容代码就能明白了 fcall = funcProto.bind ? call.bind(call) : function(f, context) { return f.apply(context, slice.call(arguments, 2)); }; // Safe array ops arrayProto = []; slice = arrayProto.slice; // ES5 reduce implementation if native not available // See: http://es5.github.com/#x15.4.4.21 as there are many // specifics and edge cases. ES5 dictates that reduce.length === 1 // This implementation deviates from ES5 spec in the following ways: // 1. It does not check if reduceFunc is a Callable // 对[].reduce的兼容性处理 reduceArray = arrayProto.reduce || function(reduceFunc /*, initialValue */) { /*jshint maxcomplexity: 7*/ var arr, args, reduced, len, i; i = 0; arr = Object(this); len = arr.length >>> 0; args = arguments; // If no initialValue, use first item of array (we know length !== 0 here) // and adjust i to start at second item if(args.length <= 1) { // Skip to the first real element in the array for(;;) { if(i in arr) { reduced = arr[i++]; break; } // If we reached the end of the array without finding any real // elements, it's a TypeError if(++i >= len) { throw new TypeError(); } } } else { // If initialValue provided, use it reduced = args[1]; } // Do the actual reduce for(;i < len; ++i) { if(i in arr) { reduced = reduceFunc(reduced, arr[i], i, arr); } } return reduced; }; function identity(x) { return x; } function crash(fatalError) { if(typeof monitorApi.reportUnhandled === 'function') { monitorApi.reportUnhandled(); } else { enqueue(function() { throw fatalError; }); } throw fatalError; } return when; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
晚安~~
相关文章推荐
- Vue.js 源码学习八 —— HTML解析细节学习
- PureMVC(JS版)源码解析(八):Proxy类
- PIXI.js源码解析(2)——Transform
- 原创:Js解析xml文件并简单实现省市区级联菜单(并解决各浏览器兼容性问题).
- [原创]Backbone源码分析-JSMVC
- Vue.js解析(三)【从Vue.js源码角度再看数据绑定】
- 纯js 贪吃蛇游戏解析与源码
- 值得一读的js代码 源码解析,知乎答案回答
- underscore.js源码解析【集合】
- 【原创】express3.4.8源码解析之Express结构图
- The Wide and Deep Learning Model(译文+Tensorlfow源码解析) 原创 2017年11月03日 22:14:47 标签: 深度学习 / 谷歌 / tensorf
- PureMVC(JS版)源码解析:总结
- 原创:Js解析xml文件并简单实现省市区级联菜单(并解决各浏览器兼容性问题).
- C语言解析pcap文件得到HTTP信息实例(原创,附源码)
- 详解通过源码解析Node.js中cluster模块的主要功能实现
- underscore.js源码解析之函数绑定
- 原生js动画效果(源码解析)
- PureMVC(JS版)源码解析(九):View类
- Native JsBridge源码解析 深入理解JsBridge
- 源代码阅读方法 jQuery源码解析 核心模块core.js