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 相关文章推荐
JavaScript Undefined,Null类型和NaN值区别
Oct 22 Javascript
计算新浪Weibo消息长度(还可以输入119字)
Jul 02 Javascript
js switch case default 的用法示例介绍
Oct 23 Javascript
javascript简单实现命名空间效果
Mar 06 Javascript
JavaScript实现99乘法表及隔行变色实例代码
Feb 24 Javascript
Avalon中文长字符截取、关键字符隐藏、自定义过滤器
May 18 Javascript
Bootstrap树形菜单插件TreeView.js使用方法详解
Nov 01 Javascript
Mac下使用charles遇到的问题以及解决办法
Jan 10 Javascript
浅谈js的解析顺序 作用域 严格模式
Oct 23 Javascript
vue中Axios的封装与API接口的管理详解
Aug 09 Javascript
layui table 表格模板按钮的实例代码
Sep 21 Javascript
jQuery+PHP+Ajax实现动态数字统计展示功能
Dec 25 jQuery
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 Memcached + APC + 文件缓存封装实现代码
2010/03/11 PHP
php excel类 phpExcel使用方法介绍
2010/08/21 PHP
PHP中list()函数用法实例简析
2016/01/08 PHP
PHP入门教程之字符串处理技巧总结(转换,过滤,解析,查找,截取,替换等)
2016/09/11 PHP
PHP Trait代码复用类与多继承实现方法详解
2019/06/17 PHP
JS location几个方法小姐
2008/07/09 Javascript
js的压缩及jquery压缩探讨(提高页面加载性能/保护劳动成果)
2013/01/29 Javascript
jQuery多项选项卡的实现思路附样式及代码
2014/06/03 Javascript
Sublime Text 3常用插件及安装方法
2015/12/16 Javascript
jQuery 3.0 的变化及使用方法
2016/02/01 Javascript
Vue概念及常见命令介绍(1)
2016/12/08 Javascript
理解nodejs的stream和pipe机制的原理和实现
2017/08/12 NodeJs
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
Bootstrap 模态框(Modal)带参数传值实例
2017/08/20 Javascript
LayerClose弹窗关闭刷新方法
2018/08/17 Javascript
基于vue-cli3和element实现登陆页面
2019/11/13 Javascript
python安装numpy&amp;安装matplotlib&amp; scipy的教程
2017/11/02 Python
Python中pow()和math.pow()函数用法示例
2018/02/11 Python
在VS2017中用C#调用python脚本的实现
2019/07/31 Python
如何用Python来搭建一个简单的推荐系统
2019/08/07 Python
Pytorch实现的手写数字mnist识别功能完整示例
2019/12/13 Python
python将dict中的unicode打印成中文实例
2020/05/11 Python
解决django 向mysql中写入中文字符出错的问题
2020/05/18 Python
Html5游戏开发之乒乓Ping Pong游戏示例(一)
2013/01/21 HTML / CSS
Space NK美国站:英国高端美妆护肤商城
2017/05/22 全球购物
Hoover胡佛官网:美国吸尘器和洗地机品牌
2019/01/09 全球购物
英语专业个人求职自荐信
2013/09/21 职场文书
运动会闭幕式解说词
2014/02/21 职场文书
婚礼司仪主持词
2014/03/14 职场文书
奥利奥广告词
2014/03/20 职场文书
工地安全生产标语
2014/06/06 职场文书
学生干部培训方案
2014/06/12 职场文书
领导干部群众路线对照检查材料
2014/11/05 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
物业工程部主管岗位职责
2015/04/16 职场文书
会计工作自我鉴定范文
2019/06/21 职场文书