我有一个ajax代码,它工作正常:
$.ajax({
//async: false,
url: "/Tests/GetData/",
type: 'POST',
dataType: 'json',
contentType: "application/json; charset=utf-8",
success: function (data) {
$.each(data, function (i, item) {
$.ajax({
//async: false,
url: "/Tests/DoTask/",
type: 'POST',
data: { taskName: item.TaskName },
success: function () {
$("#Status").append('Task PASSED.<br/>');
},
error: function () {
$("#Status").append('Task FAILED!<br/>');
},
beforeSend: function () {
$("#Status").append('Doing task...<br/>');
}
});
});
$("#Status").append('Process completed.</span><br/>');
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$("#Status").append('Error: ' + errorThrown + '<br/>');
},
beforeSend: function () {
$("#Status").append('<br/>Process started.<br/>');
}
});
这个问题是它是异步的,所以视图控件中的消息显示无序,所以我决定在ajax中放入选项async:false但是这会导致Web应用程序被完全阻止,但是消息显示是有序的...糟糕的想法,所以我想在实现一个队列来提供ajax调用而不使用选项async:false。我用Google搜索,我发现了这个:
How can jQuery deferred be used?
在上面的代码下面:
/* Class: Buffer
* methods: append
*
* Constructor: takes a function which will be the task handler to be called
*
* .append appends a task to the buffer. Buffer will only call a task when the
* previous task has finished
*/
var Buffer = function(handler) {
var tasks = [];
// empty resolved deferred object
var deferred = $.when();
// handle the next object
function handleNextTask() {
// if the current deferred task has resolved and there are more tasks
if (deferred.isResolved() && tasks.length > 0) {
// grab a task
var task = tasks.shift();
// set the deferred to be deferred returned from the handler
deferred = handler(task);
// if its not a deferred object then set it to be an empty deferred object
if (!(deferred && deferred.promise)) {
deferred = $.when();
}
// if we have tasks left then handle the next one when the current one
// is done.
if (tasks.length > 0) {
deferred.done(handleNextTask);
}
}
}
// appends a task.
this.append = function(task) {
// add to the array
tasks.push(task);
// handle the next task
handleNextTask();
};
};
看起来很有希望,所以我决定尝试一下,所以我修改了我的ajax代码并在结果下面,注意我已经替换了内部ajax块:
$.ajax({
//async: false,
url: "/Tests/GetData/",
type: 'POST',
dataType: 'json',
contentType: "application/json; charset=utf-8",
success: function (data) {
$.each(data, function (i, item) {
Buffer({
//async: false,
url: "/Tests/DoTask/",
type: 'POST',
data: { taskName: item.TaskName },
success: function () {
$("#Status").append('Task done.<br/>');
},
error: function () {
$("#Status").append('Task failed!<br/>');
},
beforeSend: function () {
$("#Status").append('Doing task...<br/>');
}
});
});
$("#Status").append('Process completed.</span><br/>');
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$("#Status").append('Error: ' + errorThrown + '<br/>');
},
beforeSend: function () {
$("#Status").append('<br/>Process started.<br/>');
}
});
我不确定如果我正确使用缓冲区的调用,肯定不是因为我在控制器中的操作DoTask中放了一个断点而且从不停止所以我没有正确排队每个任务,调用Buffer似乎不正确....那么我做错了什么?
首次尝试(来自Paul Grime的解决方案): 我已经完成了你的解决方案,但我正在尝试修改一些我无法做到的事情:
1)我的DoTask返回一个http代码200(如果任务完成正常)或500(如果任务没有完成正常)HttpStatusCodeResult(HttpStatusCode.OK)/ HttpStatusCodeResult(HttpStatusCode.NotFound)所以在显示的字符串中(该字符串开始完成...)我想添加doTask的结果,例如:
如果doTask完成了任务,那么:
“结果”:“通过”=&gt;完成{“结果”:“通过”,......}
如果doTask没有正确完成任务:
“结果”:“失败”=&gt;完成{“结果”:“失败”,......}
2)我已经对我的任务进行了分组,所以首先我开始执行一种任务,然后当这些任务完成时,如果它们没有问题就独立,我需要启动下一类要完成的任务,并且那么...如何修改你的代码呢?
第二次尝试:
控制器:
[HttpPost]
public JsonResult GetData()
{
var data = (dynamic)null;
using (BBDDContext context = new BBDDContext())
{
data = context.MyObject.Where(o => o.TypeId == 1).OrderBy(k => k.Name).Select(obj => new
{
name =obj.Name,
description =obj.Description
}).ToList();
}
return Json(data, JsonRequestBehavior.AllowGet);
}
查看:
function getTasks() {
return ajax({
url: "/Tests/GetData/",
type: 'POST',
dataType: 'json',
contentType: "application/json; charset=utf-8"
}).then(function (data) {
// data contains a list of pairs [Name IP]
return ok(createObject("status", "ok", "op", "getTasks", "data", JSON.stringify(data)));
}, function () {
return ok(createObject("status", "fail", "op", "getTasks"));
});
}
由于某种原因,在尝试打印“收到的GetData结果...”时,第一部分(“状态”,“确定”,“操作”,“getTasks”)被遗漏,只有最后一部分,与“数据”相关“打印(显示)。
答案 0 :(得分:1)
This jsfiddle (jQuery 1.10.1)和this jsfiddle (jQuery 1.7.2)可能会帮助您入门(差异是1.10.1版本使用Deferred.then()
而1.7.2版本使用Deferred.pipe()
。
当我使用deferreds / promises时,我试图寻找的是我减少了callback hell,或者更简单地说,降低了嵌套异步回调引入的嵌套级别。
首先,从识别逻辑功能开始,然后将其重构为命名良好的函数,每个函数都返回延迟。
function getTasks() {
return ajax({
// replace original URL with jsfiddle URL and test data
//url: "/Tests/GetData/",
url: "/echo/json/",
data: jsFiddleData(fakeTasks),
type: 'POST',
dataType: 'json',
contentType: "application/json; charset=utf-8"
}).then(function(data) {
return ok(createObject("status", "ok", "op", "getTasks", "data", data));
}, function() {
return ok(createObject("status", "fail", "op", "getTasks"));
});
}
function doTask(task) {
return ajax({
// replace original URL with jsfiddle URL and test data
//url: "/Tests/DoTask/",
//data: {
// taskName: task.TaskName
//},
// + "?" + task.TaskName for cache-busting
url: "/echo/json/" + "?" + task.TaskName,
data: jsFiddleData({
"status": "doing " + task.TaskName
}),
type: 'POST',
dataType: 'json'
}).then(function(data) {
return ok(createObject("status", "ok", "op", "doTask", "task", task, "data", data));
}, function() {
return ok(createObject("status", "fail", "op", "doTask", "task", task));
});
}
function doTasks(tasks) {
// Create a deferred for each task by calling doTask().
var deferreds = $(tasks).map(function (i, task) {
postStatus("Sending DoTask request: " + i + "," + JSON.stringify(task));
return doTask(task);
}).toArray();
// return a composite deferred which will
// wait for each of the doTask requests.
return $.when.apply($, deferreds);
}
您的应用代码最终会看起来像:
getTasks().then(function (tasks) {
postStatus("Received GetData results");
return doTasks(tasks);
}).then(function (results) {
postStatus("Received DoTask results");
for (var i = 0; i < results.length; i++) {
postStatus('done ' + JSON.stringify(results[i]));
}
}).fail(function (err) {
postStatus("Error: " + JSON.stringify(err));
});
事实上,如果没有console.log
的某些内容,并且通过一些函数重构,它可以更好地读取:
function showResults(results) {
postStatus("Received DoTask results");
for (var i = 0; i < results.length; i++) {
postStatus('done ' + JSON.stringify(results[i]));
}
}
getTasks().then(doTasks).then(showResults).fail(function (err) {
postStatus("Error: " + JSON.stringify(err));
});