现在,用回调处理一些复杂的逻辑,显得代码臃肿,难于阅读,特别是异步,嵌套。

解决这样的问题,可以是之前所说的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); });

晚安~~

【原创】when.js2.7.1源码解析的更多相关文章

  1. 【原创】backbone1.1.0源码解析之View

    作为MVC框架,M(odel)  V(iew)  C(ontroler)之间的联系是必不可少的,今天要说的就是View(视图) 通常我们在写逻辑代码也好或者是在ui组件也好,都需要跟dom打交道,我们 ...

  2. 【原创】backbone1.1.0源码解析之Collection

    晚上躺在床上,继续完成对Backbone.Collection的源码解析. 首先讲讲它用来干嘛? Backbone.Collection的实例表示一个集合,是很多model组成的,如果用model比喻 ...

  3. 【原创】express3.4.8源码解析之中间件

    前言 注意:旧文章转成markdown格式. 中间件(middleware)的概念来自于TJ的connect库,express就是建立在connect之上. 就如同connect的意思是 连接 一样, ...

  4. 【原创】angularjs1.3.0源码解析之directive

    # Angular指令编译原理 前言 angular之所以使用起来很方便,是因为通常我们只需要在html里面引入一个或多个(自定义或内置的)指令就可以完成一个特定的功能(这也是angular推荐的方式 ...

  5. 【原创】angularjs1.3.0源码解析之scope

    Angular作用域 前言 之前我们探讨过Angular的执行流程,在一切准备工作就绪后(我是指所有directive和service都装载完毕),接下来其实就是编译dom(从指定的根节点开始遍历do ...

  6. 【原创】angularjs1.3.0源码解析之执行流程

    Angular执行流程 前言 发现最近angularjs在我厂的应用变得很广泛,下周刚好也有个angular项目要着手开始做,所以先做了下功课,从源代码开始入手会更深刻点,可能讲的没那么细,侧重点在于 ...

  7. 【原创】backbone1.1.0源码解析之Model

    趁热打铁,将Backbone.Model的源代码注释也发出来. Model是用来干嘛的?写过mvc的同学应该都知道,说白了就是model实例用来存储数据表中的一行数据(row) Backbone利用m ...

  8. 【原创】express3.4.8源码解析之Express结构图

    前记 最近为了能够更好的搭建博客,看了开源博客引擎ghost源代码,顺道更深入的去了解express这个出名的nodejs web framework. 所以接下来一段时间对expressjs做一个源 ...

  9. 【原创】angularjs1.3.0源码解析之service

    Angular服务 在angular中,服务(service)是以提供特定的功能的形式而存在的. angular本身提供了很多内置服务,比如: $q: 提供了对promise的支持. $http: 提 ...

随机推荐

  1. 用 IIS 搭建 mercurial server

    mercurial server 对于代码管理工具,更多的人可能对 Git 更熟悉一些(Git太火了).其实另外一款分布式代码管理工具也被广泛的使用,它就是 mercurial.当多人协作时最好能够通 ...

  2. Github相册博客搭建

    前一段时间我看见一个问答,大概意思就是程序员都是怎么用自己的专业技能逗女朋友或表白的. 看了很多,有写定时关机脚本恶搞的,也有简单写个html展示的,其中最著名的就是几年前有个人写了个网页记录他们在一 ...

  3. 1.0.0 Unity零基础入门——打砖块

    1)设置好相应场景 2)创建脚本挂载到相应物体上并编写 2.代码 //Shoot - - 控制小球生成与射击 using System.Collections; using System.Collec ...

  4. python 游戏(数字推理游戏Bagels)

    1.游戏思路和流程图 实现功能:玩家猜测三位不一样的数字,猜错了有提示,提示分别为(位置错误数字正确),(位置和数字正确),(数字和位置都不正确) 游戏流程图 2. 使用模块和游戏提示 import ...

  5. IOTA price analysis

    Iota coinchart Look at the trendline drawn in red color, at the very first beginning of this month, ...

  6. PHP Laravel Install and Quickstart

    1.安装Laravel 一键安装包Laravel 要安装Laravel依赖的PHP7以上版本,以及php 扩展php-openssl php-pdo ... 以及Homestead github下载安 ...

  7. Intellij Idea 创建JavaWeb项目入门(一)

    Idea创建JavaWeb项目步骤:1.打开Intellij Idea IDE,然后点击Create New Project 2.左侧选择Java Enterprise,右侧选择Web Applica ...

  8. spring-boot随笔

    配置了spring-boot-starter-web的依赖后,会自动添加tomcat和spring mvc的依赖,那么spring boot 会对tomcat和spring mvc进行自动配置 < ...

  9. HTTP 协议(2)

    一.URL HTTP 是一个基于 TCP 的应用层协议,其中 HTTP1.1 版本中支持持续的连接机制(Keep-alive),绝大多数的 WEB 开发都是基于 HTTP 的应用. HTTP 的 UR ...

  10. JMeter学习笔记——认识JMeter(1)

    拿到一个自动化测试工具,我们第一步就应该了解它能提供我们哪方面的功能(最直接的方法就是从官网获取),接下来就是简单的对这个工具进行“功能测试”了,当然这里的功能测试不是让你找它存在的bug,而是让自己 ...