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 相关文章推荐
document.getElementById介绍
Sep 13 Javascript
jquery图片不完全按比例自动缩小的简单代码
Jul 29 Javascript
js从Cookies里面取值的简单实现
Jun 30 Javascript
js实现鼠标感应向下滑动隐藏菜单的方法
Feb 20 Javascript
JQuery中Text方法用法实例分析
May 18 Javascript
JavaScript实现的Tween算法及缓冲特效实例代码
Nov 03 Javascript
jquery中键盘事件小结
Feb 24 Javascript
让浏览器崩溃的12行JS代码(DoS攻击分析及防御)
Oct 10 Javascript
利用JS实现点击按钮后图片自动切换的简单方法
Oct 24 Javascript
AngularJs 终极购物车(实例讲解)
Nov 08 Javascript
Angular8 Http拦截器简单使用教程
Aug 20 Javascript
利用layer实现表单完美验证的方法
Sep 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
DedeCMS 核心类TypeLink.class.php摘要笔记
2010/04/07 PHP
php中3种方法统计字符串中每种字符的个数并排序
2012/08/27 PHP
php在window iis的莫名问题的测试方法
2013/05/14 PHP
PHP实现显示照片exif信息的方法
2014/07/11 PHP
Laravel框架实现发送短信验证功能代码
2016/06/06 PHP
PHP生成静态HTML文档实现代码
2016/06/23 PHP
精解window.setTimeout()&amp;window.setInterval()使用方式与参数传递问题!
2007/11/23 Javascript
JavaScript中函数声明优先于变量声明的实例分析
2012/03/01 Javascript
js对列表中第一个值处理与jsp页面对列表中第一个值处理的区别详解
2013/11/05 Javascript
javascript结合ajax读取txt文件内容
2014/12/05 Javascript
jQuery学习笔记之基础中的基础
2015/01/19 Javascript
AngularJS iframe跨域打开内容时报错误的解决办法
2015/01/26 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
JS模拟实现方法重载示例
2016/08/03 Javascript
利用AngularJs实现京东首页轮播图效果
2016/09/08 Javascript
bootstrap table 多选框分页保留示例代码
2017/03/08 Javascript
jQuery remove()过滤被删除的元素(推荐)
2017/07/18 jQuery
微信小程序进入广告实现代码实例
2019/09/19 Javascript
vue element自定义表单验证请求后端接口验证
2019/12/11 Javascript
Vue+Element-U实现分页显示效果
2020/11/15 Javascript
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
2021/01/22 Vue.js
python求素数示例分享
2014/02/16 Python
深入理解python函数递归和生成器
2016/06/06 Python
python实现桌面气泡提示功能
2019/07/29 Python
Python爬虫开发与项目实战
2020/12/16 Python
荷兰在线钓鱼商店:Raven
2019/06/26 全球购物
Timberland德国官网:靴子、鞋子、衣服、夹克及配件
2019/12/10 全球购物
优秀毕业自我鉴定
2014/02/15 职场文书
党员领导干部民主生活会批评与自我批评发言
2014/09/28 职场文书
公司给客户的感谢信
2015/01/23 职场文书
感恩主题班会教案
2015/08/12 职场文书
范文之农村基层党建工作报告
2019/10/24 职场文书
创作书写之导游词实用技巧分享(干货)
2019/12/20 职场文书
90行Python代码开发个人云盘应用
2021/04/20 Python
《艾尔登法环》发布最新「战技」宣传片
2022/04/03 其他游戏
box-shadow单边阴影的实现
2023/05/21 HTML / CSS