所以我试图在一个非常慢和长的查询上添加一个异步进度条,它将一堆行插入数据库。我的实现基于此示例:http://blog.janjonas.net/2012-01-02/asp_net-mvc_3-async-jquery-progress-indicator-long-running-tasks
以下是进度条的JavaScript代码
function updateMonitor(taskId, status) {
$("#monitors").html("Task [" + taskId + "]: " + status);
}
//other code
if (doSend == true) {
$.post("/SendBatch/HandleBatchRequest", {
//other code
},
function (taskId) {
// Init monitors
//breakpoint here only stops it once the "/SendBatch/HandleBatchRequest" is done. PROBLEM.
$("#monitors").append($("<p id='" + taskId + "'/>"));
updateMonitor(taskId, "Started");
// Periodically update monitors
var intervalId = setInterval(function () {
$.post("SendBatch/Progress", { id: taskId }, function (progress) {
if (progress >= 100) {
updateMonitor(taskId, "Completed");
clearInterval(intervalId);
} else {
updateMonitor(taskId, progress + "%");
}
});
}, 100);
}
,"html");
然后在网站的显示部分有DIV
<div id="monitors"></div>
以下是控制器的外观
public SendBatchController
//some code
private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>();
public ActionResult HandleBatchRequest(
//some code
)
{
var taskId = Guid.NewGuid();
tasks.Add(taskId, 0);
var batchId = Guid.NewGuid().ToString("N");
var costd = cost.ToDecimal();
IEnumerable<BatchListModel> customers;
try
{
customers = new CustomerService(_customerRepository.Session).GetCustomers(
//some code
);
}
catch (Exception err)
{
return Json(err.Message);
}
if (doSend)
{
var sent = 0;
foreach (var c in customers)
{
try
{
var usr = _customerRepository.LoadByID(c.ID);
var message = new ComLog
{
//insertions to log
};
_comLogRepository.Save(message);
sent++;
//progress bar part inside here that is important comes here:
tasks[taskId] = sent;
}
catch (Exception e)
{
Log.WriteLine("ERR:" + e);
}
tasks.Remove(taskId);
}
return Json(taskId);
}
return Json(customers.Count() + " customers");
}
public ActionResult Progress(Guid id)
{
return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
}
这不起作用。该过程在后台运行。查询完成后,DIV会显示“完成”消息。它在查询期间不显示。我不确定异步东西是如何工作的,因此这里可能存在一些逻辑错误。例如,它甚至知道总共有多少客户?代码的另一个关键部分是“tasks [taskId] = sent;”我不确定是否正确完成。
答案 0 :(得分:1)
在javascript方面,开始进度检查的函数在成功完成HandleBatchRequest
请求之后才会触发。 $.post()
的第三个参数是成功请求后触发的内容。
您需要让C#控制器立即返回任务ID,然后将数据库插件转移到另一个线程/后台工作程序中(详见下文)。或者让Javascript随机生成taskId并传递给C#控制器。
从那里开始,正如Brad所说,你不想在其中使用ajax请求来执行setInterval。由于AJAX是异步的,因此您可能会在服务器返回响应之前等待一段时间。为了防止一次发生多个请求并在后端服务器上造成撤消压力,您需要执行以下操作:
var taskId = 0;
$.post('/SendBatch/HandleBatchRequest', {}, function(r) {
taskId = r; // set task id from
$("#monitors").append($("<p id='" + taskId + "'/>"));
CheckProgress();
}, 'html');
function CheckProgress() {
$.post("SendBatch/Progress", { id: taskId }, function (progress) {
if (progress >= 100) {
updateMonitor(taskId, "Completed");
} else {
updateMonitor(taskId, progress + "%");
setTimeout(function() {
CheckProgress()
}, 1000);
}
}
在C#方面,控制器会在每个Web请求上实例化,因此当您检查进度时,tasks
将为空。您需要将实际记录卸载到某种后台工作者/线程中,该后台工作者/线程执行从控制器插入记录的实际工作。如果您经常这样做,您可能需要查看服务器本身安装的某种后台服务,这些服务会不断运行以优化事物并为您提供最佳的灵活性。
答案 1 :(得分:0)
我强烈建议不要在setInterval函数中使用ajax。而是在$ .post()的success / complete回调函数中使用setTimeout。这将保证请求是按顺序生成的。
如果每100毫秒发出一次Ajax请求,它们很快就会失去同步,无疑会导致问题。
答案 2 :(得分:0)
为什么不在你的网站上添加一个加载gif(你可以在这里下载它们 - http://www.ajaxload.info/)然后把这个加载gif放在页面上的div中 - 无论你想要显示它。
如下所示
<div><img class="hidden " id="LoadingGif" src='../Content/Styles/images/loading.gif' height="100" /></div>
然后在你的js文件中删除隐藏在LoadingGif id上的类,并可能将隐藏的类添加到你的监视器div。
隐藏的类应该在您的site.css中如下所示
.hidden {visibility:hidden; display:none;}