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 的方法重载效果
Aug 07 Javascript
修复ie8&amp;chrome下window的resize事件多次执行
Oct 20 Javascript
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
Nov 14 Javascript
jquery easyui使用心得
Jul 07 Javascript
jQuery地图map悬停显示省市代码分享
Aug 20 Javascript
去除html代码里面的script正则方法
May 19 Javascript
基于jQuery对象和DOM对象和字符串之间的转化实例
Aug 08 jQuery
vue中实现先请求数据再渲染dom分享
Mar 17 Javascript
JS逻辑运算符短路操作实例分析
Jul 09 Javascript
vue观察模式浅析
Sep 25 Javascript
150行Node.js实现的dns代理工具
Aug 02 Javascript
浅谈vue中$bus的使用和涉及到的问题
Jul 28 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打开远程文件的方法和风险及解决方法
2013/11/12 PHP
Windows中使用计划任务自动执行PHP程序实例
2014/05/09 PHP
PHP实现的增强性mhash函数
2015/05/27 PHP
PHP 文件上传后端处理实用技巧方法
2017/01/06 PHP
jQuery旋转插件—rotate支持(ie/Firefox/SafariOpera/Chrome)
2013/01/16 Javascript
js判断屏幕分辨率的代码
2013/07/16 Javascript
禁止ajax缓存获取程序最新数据的方法
2013/11/19 Javascript
javascript获取浏览器类型和版本的方法(js获取浏览器版本)
2014/03/13 Javascript
使用jQuery仿苹果官网焦点图特效
2014/12/23 Javascript
jquery判断复选框选中状态以及区分attr和prop
2015/12/18 Javascript
百度搜索框智能提示案例jsonp
2016/11/28 Javascript
谈谈Vue.js——vue-resource全攻略
2017/01/16 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
javascript基本常用排序算法解析
2017/09/27 Javascript
jQuery实现监听下拉框选中内容发生改变操作示例
2018/07/13 jQuery
GOJS+VUE实现流程图效果
2018/12/01 Javascript
JavaScript 替换所有匹配内容及正则替换方法
2020/02/12 Javascript
vue 二维码长按保存和复制内容操作
2020/09/22 Javascript
[52:29]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第三局
2016/03/03 DOTA
浅析Python中的多进程与多线程的使用
2015/04/07 Python
把项目从Python2.x移植到Python3.x的经验总结
2015/04/20 Python
深入学习Python中的装饰器使用
2016/06/20 Python
Python装饰器(decorator)定义与用法详解
2018/02/09 Python
python获取代码运行时间的实例代码
2018/06/11 Python
Python不使用int()函数把字符串转换为数字的方法
2018/07/09 Python
利用python实现汉字转拼音的2种方法
2019/08/12 Python
纯CSS3实现自定义Tooltip边框涂鸦风格的教程
2014/11/05 HTML / CSS
css3学习系列之移动属性详解
2017/07/04 HTML / CSS
canvas绘制图片drawImage使用方法
2020/09/15 HTML / CSS
struct和class的区别
2015/11/20 面试题
《雨霖铃》教学反思
2014/02/22 职场文书
运动会演讲稿300字
2014/08/25 职场文书
2014年质检员工作总结
2014/11/18 职场文书
2015年乡镇平安建设工作总结
2015/05/13 职场文书
优秀的商业计划书,让融资一步到位
2019/05/07 职场文书
使用tensorflow 实现反向传播求导
2021/05/26 Python