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 hasFocus使用实例
Jun 29 Javascript
js模仿jquery的写法示例代码
Jun 16 Javascript
js 浏览本地文件夹系统示例代码
Oct 24 Javascript
javascript if条件判断方法小结
May 17 Javascript
使用JSON作为函数的参数的优缺点
Oct 27 Javascript
快速入门Vue
Dec 19 Javascript
jQuery给表格添加分页效果
Mar 02 Javascript
Vue 2.0 服务端渲染入门介绍
Mar 29 Javascript
jQuery上传插件webupload使用方法
Aug 01 jQuery
Vue上传组件vue Simple Uploader的用法示例
Aug 25 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
Dec 28 Javascript
JavaScript canvas绘制圆弧与圆形
Feb 18 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的静态成员函数效率更高的原因
2014/06/13 PHP
使用php完成常见的文件上传功能(推荐)
2017/01/13 PHP
PHP实现腾讯与百度坐标转换
2017/08/05 PHP
AngularJS中的包含详细介绍及实现示例
2016/07/28 Javascript
Listloading.js移动端上拉下拉刷新组件
2016/08/04 Javascript
Node.js设置CORS跨域请求中多域名白名单的方法
2017/03/28 Javascript
详解layui中的树形关于取值传值问题
2018/01/16 Javascript
JS实现json对象数组按对象属性排序操作示例
2018/05/18 Javascript
详解vue-cli 构建项目 vue-cli请求后台接口 vue-cli使用axios、sass、swiper
2018/05/28 Javascript
JavaScript中AOP的实现与应用
2019/05/06 Javascript
简单了解JavaScript弹窗实现代码
2020/05/07 Javascript
Python continue语句用法实例
2014/03/11 Python
整理Python 常用string函数(收藏)
2016/05/30 Python
浅析python中的分片与截断序列
2016/08/09 Python
Python进程间通信Queue实例解析
2018/01/25 Python
Python实现登陆文件验证方法
2018/10/06 Python
Python爬虫:url中带字典列表参数的编码转换方法
2019/08/21 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
Python reshape的用法及多个二维数组合并为三维数组的实例
2020/02/07 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
TensorFlow-gpu和opencv安装详细教程
2020/06/30 Python
HTML5 Canvas 起步(2) - 路径
2009/05/12 HTML / CSS
详解如何解决使用JSON.stringify时遇到的循环引用问题
2021/03/23 Javascript
机电专业大学生求职信
2013/10/04 职场文书
人事主管岗位职责范本
2013/12/04 职场文书
木工主管岗位职责
2013/12/08 职场文书
出纳担保书范文
2014/04/02 职场文书
歌唱比赛策划方案
2014/06/06 职场文书
2014预备党员批评与自我批评思想汇报
2014/09/20 职场文书
师德师风自我剖析材料
2014/09/27 职场文书
建筑工地文明标语
2014/10/09 职场文书
2014年英语教师工作总结
2014/12/03 职场文书
三年级上册科学教学计划
2015/01/21 职场文书
晚会闭幕词
2015/01/28 职场文书
怎样写辞职信
2015/02/27 职场文书
2020年元旦祝福语录,总有适合你的
2019/12/31 职场文书