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 相关文章推荐
基于javascript 闭包基础分享
Jul 10 Javascript
可自定义速度的js图片无缝滚动示例分享
Jan 20 Javascript
在myeclipse中如何加入jquery代码提示功能
Jun 03 Javascript
jQuery拖动元素并对元素进行重新排序
Dec 30 Javascript
基于JS实现翻书效果的页面切换样式
Feb 16 Javascript
bootstrap日期控件问题(双日期、清空等问题解决)
Apr 19 Javascript
bootstrap3-dialog-master模态框使用详解
Aug 22 Javascript
详解vue组件开发脚手架
Jun 15 Javascript
详解swipe使用及竖屏页面滚动方法
Jun 28 Javascript
JavaScript实现栈结构Stack过程详解
Mar 07 Javascript
javascript设计模式 ? 中介者模式原理与用法实例分析
Apr 20 Javascript
Vue的全局过滤器和私有过滤器的实现
Apr 20 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
抓取YAHOO股票报价的类
2009/05/15 PHP
PHP 处理TXT文件(打开/关闭/检查/读取)
2013/05/13 PHP
Zend Studio 实用快捷键一览表(精心整理)
2013/08/10 PHP
php 判断是否是中文/英文/数字示例代码
2013/09/30 PHP
用js 让图片在 div或dl里 居中,底部对齐
2008/01/21 Javascript
js 动态选中下拉框
2009/11/26 Javascript
关于js中alert弹出窗口文本换行问题简单详细说明
2012/12/11 Javascript
Jquery多选框互相内容交换的实例代码
2013/07/04 Javascript
js的匿名函数使用介绍
2013/12/11 Javascript
谈谈js中的prototype及prototype属性解释和常用方法
2015/11/25 Javascript
JavaScript中Object.prototype.toString方法的原理
2016/02/24 Javascript
用jQuery向div中添加Html文本内容的简单实现
2016/07/13 Javascript
yarn与npm的命令行小结
2016/10/20 Javascript
Bootstrap基本模板的使用和理解1
2016/12/14 Javascript
Angular2 PrimeNG分页模块学习
2017/01/14 Javascript
Vue中jsx不完全应用指南小结
2019/11/01 Javascript
Python的Tornado框架异步编程入门实例
2015/04/24 Python
python实现爬虫下载美女图片
2015/07/14 Python
Pycharm在创建py文件时,自动添加文件头注释的实例
2018/05/07 Python
Python3简单实现串口通信的方法
2019/06/12 Python
在Python3 numpy中mean和average的区别详解
2019/08/24 Python
Django User 模块之 AbstractUser 扩展详解
2020/03/11 Python
Python 实现国产SM3加密算法的示例代码
2020/09/21 Python
HTML5新增的标签和属性归纳总结
2018/05/02 HTML / CSS
Bulk Powders意大利:运动补充在线商店
2019/02/09 全球购物
Michael Kors加拿大官网:购买设计师手袋、手表、鞋子、服装等
2019/03/16 全球购物
英国玛莎百货澳大利亚:Marks & Spencer Australia
2019/08/30 全球购物
PHP面试题集
2016/12/18 面试题
策划总监岗位职责
2014/02/16 职场文书
大学毕业感言200字
2014/03/09 职场文书
聘任书的写作格式及范文
2014/03/29 职场文书
购房协议书范本
2014/04/11 职场文书
企业宣传工作方案
2014/06/02 职场文书
Vue-Element-Admin集成自己的接口实现登录跳转
2021/06/23 Vue.js
Spring Data JPA框架Repository自定义实现
2022/04/28 Java/Android
在虚拟机中安装windows server 2008的图文教程
2022/06/28 Servers