Никогда нельзя предсказать в какой последовательности будут отрабатываться асинхронные запросы. Зачастую важен только ответ на самый последний запрос, а предыдущие запросы можно просто проигнорировать.
var concurrent = (function () {
var concurrentRequests = {};
return function (opts, cache) {
// вместо jqXHR функция будет возвращать promise-объект
var deferred = $.Deferred(), promise = deferred.promise();
// сохраняем колбеки, если они есть
promise.done(opts.success || $.noop);
promise.fail(opts.error || $.noop);
promise.always(opts.complete || $.noop);
// удаляем колбеки из параметров,
// так как cacheable не обрабатывает их
delete opts.success;
delete opts.error;
delete opts.complete;
// таймстемп запроса.
// ответы с таймстемпом меньше текущего игнорируются
var requestId = concurrentRequests[opts.url] = $.now();
// кеширующий или обычный запрос
(cache ? cacheable : $.ajax)(opts)
.done(function () {
if (concurrentRequests[opts.url] <= requestId) {
deferred.resolveWith(promise,
Array.prototype.slice.apply(arguments));
}
})
.fail(function () {
if (concurrentRequests[opts.url] <= requestId) {
deferred.rejectWith(promise,
Array.prototype.slice.apply(arguments));
}
});
return promise;
}
}());
В паре с функций cacheable получилась достаточно универсальная замена традиционной функции $.ajax
.
$(".list").each(function () {
var list = $(this);
list.on("click", ".list__page", function () {
concurent({
url: "/list/",
data: {page: $.tim($(this).text())},
dataType: "html"
}, true).done(function (markup) {
list.html(markup);
});
});
});