我在页面加载时有项目ID列表:
var itemIds = [1, 5, 10, 11];
将ID呈现到列表中并显示给用户。我有加载项目详细信息的功能,它返回Promise / A.
function loadInfo(id) { ... }
在页面加载时启动所有项目的信息加载:
val infos = {};
$.each(itemIds, function(i, id) { infos[id] = loadInfo(id); }
现在问题本身。
当用户点击商品ID时:
看起来很简单:
$('li').click(function() {
var id = $(this).data('item-id');
infos[id].then(function(info) { $('#info').text(info); });
});
但如果用户在加载当前项目之前就已经在另一个项目上进行了访问,那么我必须取消当前项目承诺的处理程序并安排新的项目。
如何正确地做到这一点?
我有几个工作解决方案(比如维护currentItemId变量并在promise处理程序中检查它),但它们很难看。我应该寻找反应式编程库吗?
答案 0 :(得分:0)
Kriomant,
我想有很多方法可以对此进行编码。这是一个:
var INFOS = (function(){
var infoCache = {},
promises = {},
fetching = null;
var load = function(id) {
if(!promises[id]) {
promises[id] = $ajax({
//ajax options here
}).done(function(info){
infoCache[id] = info;
delete promises[id];
});
}
return promises[id];
}
var display = function(id, $container) {
if(fetching) {
//cancel display (but not loading) of anything latent.
fetching.reject();
}
if(infoCache[id]) {
//info is already cached, so simply display it.
$container.text(infoCache[id]);
}
else {
fetching = $.Deferred().done(function() {
$container.text(infoCache[id]);
});
load(id).done(fetching.resolve);
}
}
return {
load: load,
display: display
};
})();
正如您将看到的,所有复杂性都捆绑在命名空间INFOS
中,这会暴露两种方法; load
和display
。
以下是如何调用方法:
$(function() {
itemIds = ["p7", "p8", "p9"];
//preload
$.each(itemIds, function(i, id) { INFOS.load(id); });
//load into cache on first click, then display from cache.
$('li').on('click', function() {
var id = $(this).data('item-id');
INFOS.display(id, $('#info'));
});
});
DEMO (使用模拟ajax)
这里的技巧是: