JavaScript 异步调用框架 (Part 6 - 实例 & 模式)


Posted in Javascript onAugust 04, 2009

封装Ajax
设计Async.Operation的最初目的就是解决Ajax调用需要传递callback参数的问题,为此我们先把Ajax请求封装为Async.Operation。我在这里使用的是jQuery,当然无论你用什么基础库,在使用Async.Operation时都可以做这种简单的封装。

var Ajax = {}; Ajax.get = function(url, data) { 
var operation = new Async.Operation(); 
$.get(url, data, function(result) { operation.yield(result); }, "json"); 
return operation; 
}; 
Ajax.post = function(url, data) { 
var operation = new Async.Operation(); 
$.post(url, data, function(result) { operation.yield(result); }, "json"); 
return operation; 
};

在我所调用的服务器端API中,只需要GET和POST,且数据都为JSON,所以我就直接把jQuery提供的其它Ajax选项屏蔽掉了,并设置数据类型为JSON。在你的项目当中,也可以用类似的方式将Ajax封装为若干仅仅返回Async.Operation的方法,将jQuery提供的选项都封装在Ajax这一层内,不再向上层暴露这些选项。

调用Ajax
把Ajax封装好后,我们就可以开始专心写业务逻辑了。

假设我们有一个Friend对象,它的get方法用于返回单个好友对象,而getAll方法用于返回所有好友对象。于此对应的是两个服务器端API,friend接口会返回单个好友JSON,而friendlist接口会返回所有好友名称组成的JSON。

首先我们看看较为基础的get方法怎么写:

function get(name) { 
return Ajax.get("/friend", "name=" + encodeURIComponent(name)); 
}

就这么简单?对的,假如服务器端API返回的JSON结构正好就是你要的好友对象结构的话。如果JSON结构和好友对象结构是异构的,或许你还要加点代码来把JSON映射为对象:
function get(name) { 
var operation = new Async.Operation() 
Ajax.get("/friend", "name=" + encodeURIComponent(name)) 
.addCallback(function(json) { 
operation.yield(createFriendFromJson(json)); 
}); 
return operation; 
}

Ajax队列
接下来我们要编写的是getAll方法。因为friendlist接口只返回好友名称列表,因此在取得这份列表后我们还要逐一调用get方法获取具体的好友对象。考虑到在同时进行多个friend接口调用可能触发服务器的防攻击策略,导致被关小黑屋一段时间,所以对friend接口的调用必须排队。
function getAll(){ 
var operation = new Async.Operation(); 
var friends = []; 
var chain = Async.chain(); 
Ajax.get("/friendlist", "") 
.addCallback(function(json) { 
for (var i = 0; i < json.length; i++) { 
chain.next(function() { 
return get(json.shift()) 
.addCallback(function(friend) { friends.push(friend); }); 
}); 
} 
chain 
.next(function() { operation.yield(friends); }) 
.go(); 
}) 
return operation; 
}

在这里,我们假设friendlist接口返回的JSON就是一个Array,在获取到这个Array后构造一个等长的异步调用队列,其中每一个调用的逻辑都是一样的——取出Array中首个好友的名称,用get方法获取对应的好友对象,再将好友对象放入另一个Array中。在调用队列的末端,我们再追加了一个调用,用于返回保存好友对象的Array。

在这个例子当中,我们没有利用调用队列会把上一个函数的结果传递给下一个函数的特性,不过也足够展示调用队列的用途了——让多个底层为Ajax请求的异步操作按照固定的顺序阻塞式执行。

由于底层异步函数返回的就是Async.Operation,你可以直接把它传递给next方法,也可以用匿名函数包装后传递给next方法,而匿名函数内部只需要一个return。

延时函数
在上面的例子中,使用队列是为了避免触发服务器的防攻击策略,但有时候这还是不够的。例如说,服务器要求两个请求之间至少间隔500毫秒,否则就认为是攻击,那么我们就要在队列里面插入这个间隔了。

在原本next方法调用的匿名函数中手动加入setTimeout是一个办法,但为什么我们不写一个辅助函数来解决这类问题呢?让我们来写一个辅助方法并让它和Async.Operation无缝结合起来。

Async.wait = function(delay, context) { 
var operation = new Async.Operation(); 
setTimeout(function() { operation.yield(context); }, delay); 
return operation; 
}; Async.Operation.prototype.wait = function(delay, context) { 
this.next(function(context) { return Async.wait(delay, context); }); 
}

在有了这个辅助方法后,我们就可以在上述getAll方法中轻松实现在每个Ajax请求之间间隔500毫秒。在for循环内的加上对wait的调用就可以了。
for (var i = 0; i < json.length; i++) { 
chain 
.wait(500) 
.next(function() { 
return get(json.shift()) 
.addCallback(function(friend) { friends.push(friend); }); 
}); 
}

小结
通过一些简单的例子,我们了解到了Async.Operation常见的使用方式,以及在有需要的时候如何扩展它的功能。希望Async.Operation能够有效帮助大家提高Ajax应用的代码可读性。
Javascript 相关文章推荐
完整显示当前日期和时间的JS代码
Sep 17 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
Nov 26 Javascript
jquery插件bxslider用法实例分析
Apr 16 Javascript
js支持键盘控制的左右切换立体式图片轮播效果代码分享
Aug 26 Javascript
JavaScript实现算术平方根算法-代码超简单
Sep 11 Javascript
jQuery鼠标悬浮链接弹出跟随图片实例代码
Jan 08 Javascript
jQuery.uploadify文件上传组件实例讲解
Sep 23 Javascript
如何抽象一个Vue公共组件
Oct 17 Javascript
详解Vue如何支持JSX语法
Nov 10 Javascript
axios 封装上传文件的请求方法
Sep 26 Javascript
js Math数学简单使用操作示例
Mar 13 Javascript
Js实现粘贴上传图片的原理及示例
Dec 09 Javascript
javascript 支持链式调用的异步调用框架Async.Operation
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 5 - 链式实现)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 4 - 链式调用)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 3 - 代码实现)
Aug 04 #Javascript
JavaScript 异步调用框架 (Part 2 - 用例设计)
Aug 03 #Javascript
JavaScript 异步调用框架 (Part 1 - 问题 &amp; 场景)
Aug 03 #Javascript
jQuery 相关控件的事件操作分解
Aug 03 #Javascript
You might like
php缩小png图片不损失透明色的解决方法
2013/12/25 PHP
详解PHP中instanceof关键字及instanceof关键字有什么作用
2015/11/05 PHP
php数组分页实现方法
2016/04/30 PHP
php实现表单提交上传文件功能
2018/05/28 PHP
jquery判断浏览器后退时候弹出消息的方法
2014/08/11 Javascript
node.js中的Socket.IO使用实例
2014/11/04 Javascript
js实现内容显示并使用json传输数据
2016/03/16 Javascript
浅析JavaScript 箭头函数 generator Date JSON
2016/05/23 Javascript
BootStrap学习笔记之nav导航栏和面包屑导航
2017/01/03 Javascript
Vue如何引入远程JS文件
2017/04/20 Javascript
详解vue-cli项目中怎么使用mock数据
2018/05/29 Javascript
JS实现的点击按钮图片上下滚动效果示例
2019/01/28 Javascript
微信小程序利用for循环解决内容变更问题
2020/03/05 Javascript
Python进阶之尾递归的用法实例
2018/01/31 Python
Django数据库表反向生成实例解析
2018/02/06 Python
Tensorflow卷积神经网络实例进阶
2018/05/24 Python
Python 隐藏输入密码时屏幕回显的实例
2019/02/19 Python
Django+Xadmin构建项目的方法步骤
2019/03/06 Python
将python文件打包成EXE应用程序的方法
2019/05/22 Python
Python实现PyPDF2处理PDF文件的方法示例
2019/09/25 Python
python 实现批量替换文本中的某部分内容
2019/12/13 Python
使用python客户端访问impala的操作方式
2020/03/28 Python
Python文件时间操作步骤代码详解
2020/04/13 Python
Django中Q查询及Q()对象 F查询及F()对象用法
2020/07/09 Python
Css3实现无缝滚动防抖
2020/09/14 HTML / CSS
HTML5适合的情人节礼物有纪念日期功能
2021/01/25 HTML / CSS
即兴演讲稿
2014/01/04 职场文书
咖啡馆创业计划书
2014/01/26 职场文书
学习“七一”讲话精神体会
2014/07/08 职场文书
交通事故委托书范本精选
2014/10/04 职场文书
2014年城市管理工作总结
2014/12/02 职场文书
小升初自荐信范文
2015/03/05 职场文书
学生党支部工作总结2015
2015/05/26 职场文书
国际贸易实训总结
2015/08/03 职场文书
一篇合格的广告文案,其主要目的是什么?
2019/07/12 职场文书
ECharts transform数据转换和dataZoom在项目中使用
2022/12/24 Javascript