【原创】when.js2.7.1源码解析
现在,用回调处理一些复杂的逻辑,显得代码臃肿,难于阅读,特别是异步,嵌套。
解决这样的问题,可以是之前所说的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源码解析的更多相关文章
- 【原创】backbone1.1.0源码解析之View
作为MVC框架,M(odel) V(iew) C(ontroler)之间的联系是必不可少的,今天要说的就是View(视图) 通常我们在写逻辑代码也好或者是在ui组件也好,都需要跟dom打交道,我们 ...
- 【原创】backbone1.1.0源码解析之Collection
晚上躺在床上,继续完成对Backbone.Collection的源码解析. 首先讲讲它用来干嘛? Backbone.Collection的实例表示一个集合,是很多model组成的,如果用model比喻 ...
- 【原创】express3.4.8源码解析之中间件
前言 注意:旧文章转成markdown格式. 中间件(middleware)的概念来自于TJ的connect库,express就是建立在connect之上. 就如同connect的意思是 连接 一样, ...
- 【原创】angularjs1.3.0源码解析之directive
# Angular指令编译原理 前言 angular之所以使用起来很方便,是因为通常我们只需要在html里面引入一个或多个(自定义或内置的)指令就可以完成一个特定的功能(这也是angular推荐的方式 ...
- 【原创】angularjs1.3.0源码解析之scope
Angular作用域 前言 之前我们探讨过Angular的执行流程,在一切准备工作就绪后(我是指所有directive和service都装载完毕),接下来其实就是编译dom(从指定的根节点开始遍历do ...
- 【原创】angularjs1.3.0源码解析之执行流程
Angular执行流程 前言 发现最近angularjs在我厂的应用变得很广泛,下周刚好也有个angular项目要着手开始做,所以先做了下功课,从源代码开始入手会更深刻点,可能讲的没那么细,侧重点在于 ...
- 【原创】backbone1.1.0源码解析之Model
趁热打铁,将Backbone.Model的源代码注释也发出来. Model是用来干嘛的?写过mvc的同学应该都知道,说白了就是model实例用来存储数据表中的一行数据(row) Backbone利用m ...
- 【原创】express3.4.8源码解析之Express结构图
前记 最近为了能够更好的搭建博客,看了开源博客引擎ghost源代码,顺道更深入的去了解express这个出名的nodejs web framework. 所以接下来一段时间对expressjs做一个源 ...
- 【原创】angularjs1.3.0源码解析之service
Angular服务 在angular中,服务(service)是以提供特定的功能的形式而存在的. angular本身提供了很多内置服务,比如: $q: 提供了对promise的支持. $http: 提 ...
随机推荐
- 用 IIS 搭建 mercurial server
mercurial server 对于代码管理工具,更多的人可能对 Git 更熟悉一些(Git太火了).其实另外一款分布式代码管理工具也被广泛的使用,它就是 mercurial.当多人协作时最好能够通 ...
- Github相册博客搭建
前一段时间我看见一个问答,大概意思就是程序员都是怎么用自己的专业技能逗女朋友或表白的. 看了很多,有写定时关机脚本恶搞的,也有简单写个html展示的,其中最著名的就是几年前有个人写了个网页记录他们在一 ...
- 1.0.0 Unity零基础入门——打砖块
1)设置好相应场景 2)创建脚本挂载到相应物体上并编写 2.代码 //Shoot - - 控制小球生成与射击 using System.Collections; using System.Collec ...
- python 游戏(数字推理游戏Bagels)
1.游戏思路和流程图 实现功能:玩家猜测三位不一样的数字,猜错了有提示,提示分别为(位置错误数字正确),(位置和数字正确),(数字和位置都不正确) 游戏流程图 2. 使用模块和游戏提示 import ...
- IOTA price analysis
Iota coinchart Look at the trendline drawn in red color, at the very first beginning of this month, ...
- PHP Laravel Install and Quickstart
1.安装Laravel 一键安装包Laravel 要安装Laravel依赖的PHP7以上版本,以及php 扩展php-openssl php-pdo ... 以及Homestead github下载安 ...
- Intellij Idea 创建JavaWeb项目入门(一)
Idea创建JavaWeb项目步骤:1.打开Intellij Idea IDE,然后点击Create New Project 2.左侧选择Java Enterprise,右侧选择Web Applica ...
- spring-boot随笔
配置了spring-boot-starter-web的依赖后,会自动添加tomcat和spring mvc的依赖,那么spring boot 会对tomcat和spring mvc进行自动配置 < ...
- HTTP 协议(2)
一.URL HTTP 是一个基于 TCP 的应用层协议,其中 HTTP1.1 版本中支持持续的连接机制(Keep-alive),绝大多数的 WEB 开发都是基于 HTTP 的应用. HTTP 的 UR ...
- JMeter学习笔记——认识JMeter(1)
拿到一个自动化测试工具,我们第一步就应该了解它能提供我们哪方面的功能(最直接的方法就是从官网获取),接下来就是简单的对这个工具进行“功能测试”了,当然这里的功能测试不是让你找它存在的bug,而是让自己 ...