您的位置:首页 > Web前端 > JavaScript

【原创】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+后,又添加了好多扩展功能,使得在实际应用中,

能够很方便的写出优秀的代码。

所以对于这样强大的代码,当然是要去读一遍,学学作者的架构思路,花了几天时间阅读,对源代码进行了中文注释讲解(其中有放一些例子),

就贴在下面了,可能会有点长(看源代码都需要耐心嘛),如果有错误还望指证出来,多谢啦~

/** @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); });


晚安~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: