瘦人说

Mr.Deferred (Deferred Object in Mr)

进入正题之前想先聊点别的。最近我好像找到了一种学习的感觉是关于研究方向的,估计是来源于“生态圈”这个词。对的,我第一次看到别人说到什么什么生态圈时,我那时一个无头苍蝇不知道是神马东西,比如,Android系统更新了,Java升级了,HTML5 vs Silverlight等等,这些话题都会引起人们关于“生态圈”的讨论。那么我理解的生态圈是什么呢?我把它理解为生态圈就是你想了解的东西发展的环境,相互影响的事物集合。像我喜欢JS,我将会看看JS现在的发展趋势是什么,JS解释器怎么实现的,JS的优势劣势是什么,劣势要怎么改善,Nodejs服务端开发核心是什么,CommonJS标准有些什么,V8引擎我可以去看看么类似这样的事情。

我觉得我是比较能折腾的人,折腾也需要有个方向,我可能是Frank说的那种把东西试出来的花时间比较多的高手吧,最近他还评价我是招式很多但是内功不足。朋友们也说我是蛋疼君、强迫症。。。,我也虚心接受了:)。而我对自己的评价是:笨,笨得有理想。“生态圈”这个词最近突然间走进我的生活,搞得好像在学术研究方面提高了些,不过还是那句话,有很多人在我前面等着我去超越。

OK,不扯了,今天分享的就是基于CommonJS promise/A 模型的一个延迟方法的链式调用实现,我取名叫做Mr.Deferred,名字是从jQuery那copy过来的,延期的意思,它是属于Mr库的一部分。当然,jQuery在1.5版本里面就改写代码实现了此标准,我的这个只能算是一个alpha山寨版本。另外,微软针对Metro UI的程序运行时WinRT针对JS的异步调用部分,也用到了Promise模型。既然它这么被重视,看来它应该是JS生态圈中的一部分,值得了解一下。

Deferred Object

Deferred对象是代表了一个延迟,可以由Mr.Deferred()创建,它支持的方法有:

  1. resolve() 表示延迟对象延迟动作完成
  2. reject() 表示延迟对象延迟东西失败
  3. done(fn) 传入的fn对象是延迟resolve时回调函数
  4. fail(fn) 传入的fn对象是延迟对象reject时回调函数
  5. then(doneFn, failFn) 传入两个参数分别是成功时回调函数和失败时回调函数
  6. always(fn) 传入的是延迟无论成功或失败的回调函数
  7. isRejected() 和 isResolved() 状态判断方法

Deferred的实现是看了jQuery API和例子琢磨出来的,不过jQuery的实现考虑的事情要比我详细得多,比如jQuery的Deferred对象保存了一个promise对象,说真的,我还在想它是用来干嘛的。不说它也罢。Deferred对象是用来解决什么问题的呢?它提供异步操作一种链式地多回调方法注册的方式,方便地管理异步方法的状态(完成/未完成)和回调函数的执行。举个例子来说,大家在使用1.5之前版本的jQuery.ajax方法时,如何绑定多个成功事件呢?如何有效管理多个成功事件的执行顺序呢?除了指定success属性,还有别的更好的方式么?(因为指定属性的函数回调除了单一性这个缺点之外,代码可读性很差,更不说回调函数的嵌套了)。我们来看看jQuery中Deferred对象是怎么调用的。

// $.get 方法调用(只为展示给大家新的方式解决了什么)
function fn1() {
    console.log('fn 1');
}
function fn2() {
    console.log('fn 2');
}

$.get("test.php").done(function() {
  console.log("fn 3");  //
}).done([fn1, fn2]);

ajax 的 get 请求完成后会在控制台顺序输出 fn3 fn1 fn2,和注册顺序一致,实现了多事件绑定,代码简洁明了。接下来介绍一个怎么样使用我的Mr.Deferred实现的例子。

// 创建异步方法
function asynFn(){
    // 创建Deferred对象
    var dfd = Mr.Deferred();
	setTimeout(function(){
	    dfd.resolve(1, 1, 1, 1, 1);
	}, Math.random(1) * 2000);
	setTimeout(function(){
	    dfd.reject(2, 2, 2, 2, 2);
	}, Math.random(1) * 2500);
    return dfd;
}

// 直接调用异步方法
asynFn()
.done(function(arg){
	console.log('done');
	console.log(arguments);
})
.fail(function(arg){
	console.log('fail');
	console.log(arguments);
})
.then(
	function(){
		console.log('then->done');
		console.log(arguments);
	},
	function(){
		console.log('then->fail');
		console.log(arguments);
	})
.always(function(){
	console.log('always');
	console.log(arguments);
})
.then(
	function(){
		console.log('then2->done');
		console.log(arguments);
	},
	function(){
		console.log('then2->fail');
		console.log(arguments);
	});

输出结果是(成功时的结果):
done
[1, 1, 1, 1, 1]
then->done
[1, 1, 1, 1, 1]
then2->done
[1, 1, 1, 1, 1]
always
[Object { _doneFns=[3], _failFns=[3], 更多…}]  // firebug下的console显示,代表always里面的传入参数是实例本身

Mr.when

Mr.when方法是一个辅助方法,目的是为了同时处理多个Deferred对象,API为

  • Mr.when(dfd…)  参数为Deferred对象,可以传变参,如Mr.when(dfd1, dfd2, … ),when方法调用后可以使用Deferred对象拥有的所有事件注册方法done, fail, then, always和isRejected, isResolved状态判断方法。不具有resolve,reject方法。

举个例子大家就知道是同时处理是什么意思。

var asynFn = .... // 同上

function asynFn2(){
	var dfd = Mr.Deferred();
	setTimeout(function(){
		dfd.resolve(33, 33, 33);
	}, Math.random(1) * 3000);
	return dfd;
}

Mr.when( asynFn(), asynFn2() )
.done(function(){
	console.log('when:done');
	console.log(arguments);
})
.fail(function(){
	console.log('when:fail');
	console.log(arguments);
})
.always(function(){
	console.log('when:always');
	console.log(arguments);
})
.then(
	function(){
		console.log('when:then->done');
		console.log(arguments);
	},
	function(){
		console.log('when:then->fail');
		console.log(arguments);
	});

输出结果为:
when:done
[1, 1, 1, 1, 1, 33, 33, 33] // 多个deferred对象的参入参数数组,按顺序传入,如果没有就会跳过。
when:then->done
[1, 1, 1, 1, 1, 33, 33, 33] // 同上
when:always
[Object { _doneFns=[0], _failFns=[0], 更多…}, Object { _doneFns=[0], _failFns=[0], 更多…}] // firebug 显示为when方法中传入的deferred对象数组,按顺序传入。

when方法就让多个deferred对象的异步结束到所有传入的对象都结束时才会同时执行。比如,如果一个操作依赖于多个请求的结果,你可以毫不犹豫的使用此方法,它会是你的不二之选。

现在的Mr.Deferred还在雏形阶段,还有很多爽的调用方式没有加上,但是模型不会改变了,等到完善之后会merge到Mr的核心库Mr&Ms.js中,希望有兴趣的继续关注。我希望它将会成为“JS生态圈”的一部分,当然我对C#也很感兴趣,F#也打算要看一下,唉,事情真多,再想到Mr.Graph还需要把API总结出来,晕睡过去的心都有了。

Comments

Proudly published with Hexo