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 相关文章推荐
jquery键盘事件介绍
Jan 31 Javascript
Internet Explorer 11 浏览器介绍:别叫我IE
Sep 28 Javascript
js获取数组的最后一个元素
Apr 14 Javascript
JavaScript实现的类字典插入或更新方法实例
Jul 10 Javascript
JS控制按钮10秒钟后可用的方法
Dec 22 Javascript
javascript验证内容为数字以及长度为10的简单实例
Aug 20 Javascript
jQuery通过ajax快速批量提交表单数据
Oct 25 Javascript
微信小程序实现锚点定位楼层跳跃的实例
May 18 Javascript
Node之简单的前后端交互(实例讲解)
Nov 14 Javascript
百度小程序之间的页面通信过程详解
Jul 18 Javascript
vue中对象数组去重的实现
Feb 06 Javascript
JavaScript用document.write()输出换行的示例代码
Nov 26 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
亚洲咖啡有什么?亚洲咖啡产地介绍 亚洲咖啡有什么特点?
2021/03/05 新手入门
第十四节--命名空间
2006/11/16 PHP
MySQL数据库转移,access,sql server 转 MySQL 的图文教程
2007/09/02 PHP
php读取纯真ip数据库使用示例
2014/01/26 PHP
ThinkPHP验证码使用简明教程
2014/03/05 PHP
php中使用gd库实现远程图片下载实例
2015/05/12 PHP
PHP实现的购物车类实例
2015/06/17 PHP
火狐浏览器(firefox)下获得Event对象以及keyCode
2008/11/13 Javascript
JQuery获取文本框中字符长度的代码
2011/09/29 Javascript
原生的html元素选择器类似jquery选择器
2014/10/15 Javascript
Redis基本知识、安装、部署、配置笔记
2015/03/05 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
jquery使用ul模拟select实现表单美化的方法
2015/08/18 Javascript
js基础之DOM中document对象的常用属性方法详解
2016/10/28 Javascript
JQuery和PHP结合实现动态进度条上传显示
2016/11/23 Javascript
JavaScript创建对象_动力节点Java学院整理
2017/06/27 Javascript
JS实现上传图片的三种方法并实现预览图片功能
2017/07/14 Javascript
微信小程序methods中定义的方法互相调用的实例代码
2018/08/07 Javascript
vue.js中proxyTable 转发请求的实现方法
2018/09/20 Javascript
[05:09]2016国际邀请赛中国区预选赛淘汰赛首日精彩回顾
2016/06/29 DOTA
[01:48]帕吉至宝加入游戏,遗迹战场现“千劫神屠”
2018/04/07 DOTA
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
2014/10/23 Python
python使用opencv读取图片的实例
2017/08/17 Python
python实现扫描日志关键字的示例
2018/04/28 Python
Python实现去除列表中重复元素的方法总结【7种方法】
2019/02/16 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
Python3+SQLAlchemy+Sqlite3实现ORM教程
2021/02/16 Python
HTML5实践-图片设置成灰度图
2012/11/12 HTML / CSS
Html5原创俄罗斯方块(基于canvas)
2019/01/07 HTML / CSS
印度尼西亚值得信赖的第一家网店:Bhinneka
2018/07/16 全球购物
用C语言实现文件读写操作
2013/10/27 面试题
旅游个人求职信范文
2014/01/30 职场文书
2015新学期家长寄语
2015/02/26 职场文书
赡养老人协议书范本
2015/08/06 职场文书
使用react-virtualized实现图片动态高度长列表的问题
2021/05/28 Javascript
python 经纬度求两点距离、三点面积操作
2021/06/03 Python