JavaScript 异步方法队列链实现代码分析


Posted in Javascript onJune 05, 2010

在《javascript设计模式》中对这种方法作了比较详细的描述,实现方法的链式调用,只须让在原型中定义的方法都返回调用这些方法的实例对象的引用即可,看看书中的这段代码:

(function() { 
function _$(els) { 
this.elements = []; 
for (var i = 0, len = els.length; i < len; ++i) { 
var element = els[i]; 
if (typeof element == 'string') { 
element = document.getElementById(element); 
} 
this.elements.push(element); 
} 
}; 
_$.prototype = { 
each: function(fn) { 
for ( var i = 0, len = this.elements.length; i < len; ++i ) { 
fn.call(this, this.elements[i]); 
} 
return this; 
}, 
setStyle: function(prop, val) { 
this.each(function(el) { 
el.style[prop] = val; 
}); 
return this; 
}, 
show: function() { 
var that = this; 
this.each(function(el) { 
that.setStyle('display', 'block'); 
}); 
return this; 
}, 
addEvent: function(type, fn) { 
var add = function(el) { 
if (window.addEventListener) { 
el.addEventListener(type, fn, false); 
} 
else if (window.attachEvent) { 
el.attachEvent('on'+type, fn); 
} 
}; 
this.each(function(el) { 
add(el); 
}); 
return this; 
} 
}; 
window.$ = function() { 
return new _$(arguments); 
}; 
})();

可以看到,每个方法都以”return this”结束,这就会将调用方法的对象传递给链上的下一个方法。但是,如果我们要操作的数据是通过异步请求来获得的,如何保持方法的链式调用呢?Dustin Diaz为我们提供了一种方法来保证方法的链式调用,他也是《javascript设计模式》一书的作者之一。
他首先构建了一个Queue对象,即:
function Queue() { 
// store your callbacks 
this._methods = []; 
// keep a reference to your response 
this._response = null; 
// all queues start off unflushed 
this._flushed = false; 
} 
Queue.prototype = { 
// adds callbacks to your queue 
add: function(fn) { 
// if the queue had been flushed, return immediately 
if (this._flushed) { 
fn(this._response); 
// otherwise push it on the queue 
} else { 
this._methods.push(fn); 
} 
}, 
flush: function(resp) { 
// note: flush only ever happens once 
if (this._flushed) { 
return; 
} 
// store your response for subsequent calls after flush() 
this._response = resp; 
// mark that it's been flushed 
this._flushed = true; 
// shift 'em out and call 'em back 
while (this._methods[0]) { 
this._methods.shift()(resp); 
} 
} 
};

然后用它作为工具构建我们的异步方法队列链。有了这个工具,就可以很方便的构建一个从服务器端获取内容并将其附加到选择器中的jQuery plugin。
(function($) { 
$.fn.fetch = function(url) { 
var queue = new Queue; 
this.each(function() { 
var el = this; 
queue.add(function(resp) { 
$(el).html(resp); 
}); 
}); 
$.ajax({ 
url: url, 
dataType: 'html', 
success: function(html) { 
queue.flush(html); 
} 
}); 
return this; 
}; 
})(jQuery);

这样,我们就可以异步的获取内容,并继续我们的链式调用。
$("<div/>") 
.fetch('/server/navigation.html') 
.addClass('column') 
.appendTo('#side');

查看demo页看看效果。
如果一个队列中有很多项等待对服务器端的响应进行操作,该如何处置?作者构建了这样一个方法,值得参考:
function fetchTweet(url) { 
this.queue = new Queue; 
this.tweet = ""; 
var self = this; 
ajax(url, function(resp) { 
self.tweet = resp; 
self.queue.flush(this); 
}); 
} 
fetchTweet.prototype = { 
linkify: function() { 
this.queue.add(function(self) { 
self.tweet = self.tweet.replace(/\b@(\w{1,20}\b/g, '$1'); 
}); 
return this; 
}, 
filterBadWords: function() { 
this.queue.add(function(self) { 
self.tweet = self.tweet.replace(/\b(fuck|shit|piss)\b/g, ""); 
}); 
return this; 
}, 
appendTo: function(selector) { 
this.queue.add(function(self) { 
$(self.tweet).appendTo(selector); 
}); 
return this; 
} 
};

这样,我们就可以用下面的方式来调用:
fetchTweet(url).linkify().filterBadWords().appendTo('#status');

到此,我们已经知道了如何实现异步方法链式调用,但在《Asynchronous method queue chaining in JavaScript》底部的一些评论提出的一些问题,值得思考一下。插件$.fn.fetch中仅仅只需将返回的内容附加到元素之中,Queue是否必要?而且,jQuery中的$.fn.load完全可以实现,如果Queue中只用一个回调函数,完全可以这样来写:
(function($) { 
$.fn.fetch = function(url) { 
var queue = new Queue; 
this.each(function() { 
var el = this; 
$.ajax({ 
url: url, 
type: 'get', 
dataType: 'json', 
success: function(resp) { 
$(el).html(resp['text1']); 
} 
}); 
}); 
return this; 
}; 
})(jQuery);

不知你作如何感想?
Javascript 相关文章推荐
在次封装easyui-Dialog插件实现代码
Nov 14 Javascript
suggestion开发小结以及对键盘事件的总结(针对中文输入法状态)
Dec 20 Javascript
Javascript 闭包引起的IE内存泄露分析
May 23 Javascript
文本框文本自动补全效果示例分享
Jan 19 Javascript
Jquery中ajax方法data参数的用法小结
Feb 12 Javascript
JS打开新窗口防止被浏览器阻止的方法
Jan 03 Javascript
AngularJS 视图详解及示例代码
Aug 17 Javascript
jQuery扩展+xml实现表单验证功能的方法
Dec 25 Javascript
JavaScript数据结构之链表的实现
Mar 19 Javascript
Angular.js前台传list数组由后台spring MVC接收数组示例代码
Jul 31 Javascript
ionic使用angularjs表单验证(模板验证)
Dec 12 Javascript
js实现网页版贪吃蛇游戏
Feb 22 Javascript
js 全兼容可高亮二级缓冲折叠菜单
Jun 04 #Javascript
JavaScript中使用replace结合正则实现replaceAll的效果
Jun 04 #Javascript
利用jquery操作select下拉列表框的代码
Jun 04 #Javascript
JavaScript 页面编码与浏览器类型判断代码
Jun 03 #Javascript
javascript cookie操作类的实现代码小结附使用方法
Jun 02 #Javascript
js操作select控件的几种方法
Jun 02 #Javascript
Jquery升级新版本后选择器的语法问题
Jun 02 #Javascript
You might like
PHP 错误之引号中使用变量
2009/05/04 PHP
php面向对象编程self和static的区别
2016/05/08 PHP
微信公众号OAuth2.0网页授权问题浅析
2017/01/21 PHP
jQuery 定时局部刷新(setInterval)
2010/11/19 Javascript
js函数模拟显示桌面.scf程序示例
2014/04/20 Javascript
跟我学习javascript的闭包
2015/11/16 Javascript
javascript实现网站加入收藏功能
2015/12/16 Javascript
IE8 内存泄露(内存一直增长 )的原因及解决办法
2016/04/06 Javascript
scroll事件实现监控滚动条并分页显示(zepto.js)
2016/12/18 Javascript
深入理解Angular.JS中的Scope继承
2017/06/04 Javascript
删除table表格行的实例讲解
2017/09/21 Javascript
Vue中的scoped实现原理及穿透方法
2018/05/15 Javascript
WebGL学习教程之Three.js学习笔记(第一篇)
2019/04/25 Javascript
Vue 递归多级菜单的实例代码
2019/05/05 Javascript
vue中node_modules中第三方模块的修改使用详解
2019/05/31 Javascript
JavaScript的console命令使用实例
2019/12/03 Javascript
Python实现过滤单个Android程序日志脚本分享
2015/01/16 Python
python学习 流程控制语句详解
2016/06/01 Python
用Python实现筛选文件脚本的方法
2018/10/27 Python
Python中py文件转换成exe可执行文件的方法
2019/06/14 Python
pymysql模块的使用(增删改查)详解
2019/09/09 Python
浅谈keras的深度模型训练过程及结果记录方式
2020/01/24 Python
Django单元测试中Fixtures用法详解
2020/02/25 Python
判断Threading.start新线程是否执行完毕的实例
2020/05/02 Python
python用tkinter实现一个gui的翻译工具
2020/10/26 Python
伦敦时尚生活的缩影:LN-CC
2017/01/24 全球购物
Travelstart沙特阿拉伯:廉价航班、豪华酒店和实惠的汽车租赁优惠
2019/04/06 全球购物
沙特阿拉伯排名第一的在线时尚购物应用程序:1Zillion
2020/08/08 全球购物
二年级语文教学反思
2014/02/02 职场文书
《愚公移山》教学反思
2014/02/20 职场文书
学校社会实践活动总结
2014/07/03 职场文书
鸡毛信观后感
2015/06/11 职场文书
教师节联欢会主持词
2015/07/04 职场文书
六一儿童节园长致辞
2015/07/31 职场文书
关于开学的感想
2015/08/10 职场文书
python之django路由和视图案例教程
2021/07/26 Python