JavaScript 异步方法队列链实现代码分析
本文深入解析 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); 不知您作何感想?
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
