JavaScript 异步方法队列链实现代码分析

作者:青柠

时间:2026-10-24

浏览:465

本文深入解析 JavaScript 中异步操作的链式调用实现。通过 Queue 对象管理回调队列,解决异步请求返回前保持方法链的问题,并结合 jQuery 插件开发实例,展示如何构建异步获取内容并处理 DOM 的完整流程。

文章目录

同步链式调用基础

《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 插件实现

利用该工具,可方便地构建从服务器获取内容并附加到选择器的 jQuery 插件。


代码如下:

 
(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);

不知您作何感想?

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章