JavaScript 异步调用框架 (Part 4 - 链式调用)


Posted in Javascript onAugust 04, 2009

现实开发中,要按顺序执行一系列的同步异步操作又是很常见的。还是用百度Hi网页版中的例子,我们先要异步获取联系人列表,然后再异步获取每一个联系人的具体信息,而且后者是分页获取的,每次请求发送10个联系人的名称然后取回对应的具体信息。这就是多个需要顺序执行的异步请求。
为此,我们需要设计一种新的操作方式来优化代码可读性,让顺序异步操作代码看起来和传统的顺序同步操作代码一样优雅。
传统做法
大多数程序员都能够很好的理解顺序执行的代码,例如这样子的:

var firstResult = firstOperation(initialArgument); 
var secondResult = secondOperation(firstResult); 
var finalResult = thirdOperation(secondResult); 
alert(finalResult);

其中先执行的函数为后执行的函数提供所需的数据。然而使用我们的异步调用框架后,同样的逻辑必须变成这样子:
firstAsyncOperation(initialArgument).addCallback(function(firstResult) { 
secondAsyncOperation(firstResult).addCallback(function(secondResult) { 
thirdAsyncOperation(secondResult).addCallback(function(finalResult) { 
alert(finalResult); 
}); 
}); 
});

链式写法
我认为上面的代码实在是太不美观了,并且希望能够改造为jQuery风格的链式写法。为此,我们先构造一个用例:
Async.go(initialArgument) 
.next(firstAsyncOperation) 
.next(secondAsyncOperation) 
.next(thirdAsyncOperation) 
.next(function(finalResult) { alert(finalResult); })

在这个用例当中,我们在go传入初始化数据,然后每一个next后面传入一个数据处理函数,这些处理函数按顺序对数据进行处理。
同步并存
上面的用例调用到的全部都是异步函数,不过我们最好能够兼容同步函数,让使用者无需关心函数的具体实现,也能使用这项功能。为此我们再写一个这样的用例:
Async.go(0) 
.next(function(i) { alert(i); return i + 1; }) 
.next(function(i) { 
alert(i); 
var operation = new Async.Operation(); 
setTimeout(function() { operation.yield(i + 1); }, 1000); 
return operation; 
}) 
.next(function(i) { alert(i); return i + 1; }) 
.next(function(i) { alert(i); return i; });

在上述用例中,我们期待能够看到0, 1, 2, 3的提示信息序列,并且1和2之间间隔为1000毫秒。
异步本质
一个链式调用,本质上也是一个异步调用,所以它返回的也是一个Operation实例。这个实例自然也有result、state和completed这几个字段,并且当整个链式调用完成时,result等于最后一个调用返回的结果,而completed自然是等于true。
我们可以扩展一下上一个用例,得到如下用例代码:
var chainOperation = Async.go(0) 
.next(function(i) { alert(i); return i + 1; }) 
.next(function(i) { 
alert(i); 
var operation = new Async.Operation(); 
setTimeout(function() { operation.yield(i + 1); }, 1000); 
return operation; 
}) 
.next(function(i) { alert(i); return i + 1; }) 
.next(function(i) { alert(i); return i; }); 
setTiemout(function() { alert(chainOperation.result; }, 2000);

把链式调用的返回保存下来,在链式调用完成时,它的result应该与最后一个操作的返回一致。在上述用例中,也就是3。
调用时机
尽管我们提供了一种链式调用方式,但是用户不一定会按照这种固定的方式来调用,所以我们仍然要考虑兼容用户的各种可能用法,例如说异步地用next往调用链添加操作:
var chainOperation = Async.go(0); 
chainOperation.next(function(i) { alert(i); return i + 1; }); 
setTimeout(function() { 
chainOperation.next(function(i) { 
alert(i); 
var operation = new Async.Operation(); 
setTimeout(function() { operation.yield(i + 1); }, 2000); 
return operation; 
}) 
}, 1000); 
setTimeout(function() { 
chainOperation.next(function(i) { alert(i); return i + 1; }); 
}, 2000);

在这个用例当中,用户每隔1000毫秒添加一个操作,而其中第二个操作耗时2000毫秒。也就是说,添加第三个操作时第二个操作还没返回。作为一个健壮的框架,必须要能兼容这样的使用方式。
此外我们还要考虑,用户可能想要先构造调用链,然后再执行调用链。这时候用户就会先使用next方法添加操作,再使用go方法执行。
var chainOperation = Async 
.chain(function(i) { alert(i); return i + 1; }) 
.next(function(i) { 
alert(i); 
var operation = new Async.Operation(); 
setTimeout(function() { operation.yield(i + 1); }, 2000); 
return operation; 
}) 
.go(0) 
setTimeout(function() { 
chainOperation.next(function(i) { alert(i); return i + 1; }) 
}, 1000);

在上述用例中,用户通过chain和next添加了头同步操作和异步操作各一个,然后用go执行调用链,在调用链执行完毕之前又用next异步追加了一个操作。一个健壮的框架,在这样的用例当中应该能够如同用户所期望的那样提示0, 1, 2。
小结
针对链式调用的需求,我们设计了如此多的用例,包括各种奇怪的异步调用方式。最终如何实现这样的功能呢?
Javascript 相关文章推荐
原生Js实现按的数据源均分时间点幻灯片效果(已封装)
Dec 28 Javascript
JS打印gridview实现原理及代码
Feb 05 Javascript
JavaScript设计模式之单件模式介绍
Dec 28 Javascript
js的for in循环和java里foreach循环的区别分析
Jan 28 Javascript
为何JS操作的href都是javascript:void(0);呢
Nov 12 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
Jan 08 Javascript
使用jquery给新生的th绑定hover事件的实例
Feb 10 Javascript
Vue2.0用 watch 观察 prop 变化(不触发)
Sep 08 Javascript
JavaScript实现焦点进入文本框内关闭输入法的核心代码
Sep 20 Javascript
JavaScript自执行函数和jQuery扩展方法详解
Oct 27 jQuery
node使用promise替代回调函数
May 07 Javascript
浅谈Vue 函数式组件的使用技巧
Jun 16 Javascript
JavaScript 异步调用框架 (Part 3 - 代码实现)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 2 - 用例设计)
Aug 03 #Javascript
JavaScript 异步调用框架 (Part 1 - 问题 & 场景)
Aug 03 #Javascript
jQuery 相关控件的事件操作分解
Aug 03 #Javascript
利用javascript实现一些常用软件的下载导航
Aug 03 #Javascript
jQuery 隔行换色 支持键盘上下键,按Enter选定值
Aug 02 #Javascript
一句话JavaScript表单验证代码
Aug 02 #Javascript
You might like
Windows Apache2.2.11及Php5.2.9-1的安装与配置方法
2009/06/08 PHP
一实用的实现table排序的Javascript类库
2007/09/12 Javascript
JavaScript 入门·JavaScript 具有全范围的运算符
2007/10/01 Javascript
jQuery 获取对象 定位子对象
2010/05/31 Javascript
javascript 日期时间 转换的方法
2013/02/21 Javascript
JS+CSS实现分类动态选择及移动功能效果代码
2015/10/19 Javascript
javascript巧用eval函数组装表单输入项为json对象的方法
2015/11/25 Javascript
详解JS中Array对象扩展与String对象扩展
2016/01/07 Javascript
求js数组的最大值和最小值的四种方法
2017/03/03 Javascript
weebox弹出窗口不居中显示的解决方法
2017/11/27 Javascript
vue-lazyload图片延迟加载插件的实例讲解
2018/02/09 Javascript
使用puppeteer破解极验的滑动验证码
2018/02/24 Javascript
js 实现watch监听数据变化的代码
2019/10/13 Javascript
[36:33]2018DOTA2亚洲邀请赛 4.3 突围赛 EG vs Newbee 第二场
2018/04/04 DOTA
Go语言基于Socket编写服务器端与客户端通信的实例
2016/02/19 Python
python用Pygal如何生成漂亮的SVG图像详解
2017/02/10 Python
Python学习之Django的管理界面代码示例
2018/02/10 Python
Python中py文件引用另一个py文件变量的方法
2018/04/29 Python
对Python实现累加函数的方法详解
2019/01/23 Python
完美解决python3.7 pip升级 拒绝访问问题
2019/07/12 Python
pandas DataFrame行或列的删除方法的实现示例
2019/08/02 Python
用python生成与调用cntk模型代码演示方法
2019/08/26 Python
ubuntu上安装python的实例方法
2019/09/30 Python
通过实例解析Python return运行原理
2020/03/04 Python
更新升级python和pip版本后不生效的问题解决
2020/04/17 Python
Python基于字典实现switch case函数调用
2020/07/22 Python
介绍一下Linux文件的记录形式
2012/04/18 面试题
施工人员岗位职责
2013/12/12 职场文书
财会专业大学生求职信
2014/09/26 职场文书
依法行政工作汇报材料
2014/10/28 职场文书
2015年保洁员工作总结
2015/05/04 职场文书
婚庆司仪开场白
2015/05/29 职场文书
银行培训心得体会范文
2016/01/09 职场文书
导游词之青岛崂山
2019/12/27 职场文书
详解Vue的sync修饰符
2021/05/15 Vue.js
使用goaccess分析nginx日志的详细方法
2021/07/09 Servers