Я закончил выполнение долгосрочной задачи в отдельном потоке на сервере.Затем ajax-вызов просто повторяет вызов, чтобы проверить, готов ли ответ.Таким образом, каждый ajax-запрос очень короткий.
Мое решение подходит для приложений в интрасети, но, вероятно, его нужно будет сделать более надежным для интернет-приложений.
Таким образом, html становится:
<html>
<head>
<script src="/js/jquery-1.3.2.min.js" type="text/javascript"> </script>
<script type="text/javascript">
<!--
var detailRequest = null;
function StartDetailRequest() {
detailRequest = jQuery.ajax({
type: 'GET',
url: '<%= Url.Action("EnquiryDetail", "Account", new { requestGuid = ViewData["detailRequestGuid"] }) %>',
success: function (result) {
if (result.length == 0) {
setTimeout("StartDetailRequest()", 500);
}
else {
$('#detail').html(result);
$("table tbody").each(function () { $("tr:odd", this).addClass("odd"); });
}
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
$('#detail').html('Failed to load additional information:<br />' + textStatus + '<br />' + errorThrown);
}
});
}
$(function () {
setTimeout("StartDetailRequest()", 500);
});
//-->
</script>
</head>
<body>
<h2>Account Information</h2>
<div>Some basic details here</div>
<div><button onclick="location.assign("/somewhere-else")" type="button">Go somewhere else now</button></div>
<div id="detail">
<img src="/ajax-loading-animation.gif" alt="Loading ..." />
Loading ...
</div>
</body>
</html>
На стороне сервера я делаю что-то вроде (ASP.NET MVC 2 с псевдокодом):
private Dictionary<Guid, DetailRequestObject> detailRequestList = new Dictionary<Guid, DetailRequestObject>();
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index(string id)
{
var model = GetTheBasicDetails(id);
var request = CreateDetailRequestObject(id);
CheckForTimedOutDetailRequests();
detailRequestList.Add(request.Guid, request);
ViewData["detailRequestGuid"] = request.Guid;
return View(model);
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult EnquiryDetail(Guid requestGuid)
{
DetailRequestObject detailRequest = detailRequestList[requestGuid];
if (detailRequest == null)
{
throw new TimeoutException("Timed out retrieving details");
}
else if (!detailRequest.IsComplete)
{
return Content("");
}
else
{
var details = detailRequest.Response();
return PartialView(details);
}
}
Класс DetailRequestObject
инкапсулирует создание отдельного потока с использованием асинхронногомодель по вашему выбору, устанавливает флаг после завершения и собирает данные ответа.
У меня также есть метод CheckForTimedOutDetailRequests
, который собирает запросы, для которых истек тайм-аут для извлечения, так что любые, которые были «прерваны», могут бытьпрояснилось.
Думаю, я бы предпочел, чтобы долго выполняющиеся запросы выполнялись в отдельной службе Windows, которая выполняла бы свою собственную очистку, регулирование запросов и тому подобное, но вышеприведенное работает так ...