-1

我有下面的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/>');
           }
       });

这样做的问题是它是异步的,因此视图控件中的消息显示无序,所以我决定将选项 async:false 放入 ajax 中,但这会导致 Web 应用程序完全阻塞,尽管消息显示是有序的......坏主意,所以我想在实现一个队列来服务 ajax 调用而不使用选项 async:false。我用谷歌搜索,我找到了这个:

如何使用 jQuery 延迟?

在上述页面的代码下方:

/* 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) 所以在显示的字符串中(那个以 done 开头的字符串。 ..) 我想添加 doTask 的结果,例如:

如果 doTask 已经完成了任务:

“结果”:“通过”=> 完成 {“结果”:“通过”,...}

如果 doTask 没有正确完成任务:

“结果”:“失败”=> 完成 {“结果”:“失败”,...}

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"));
    });
}

出于某种原因,当尝试打印“Received GetData results...”时,第一部分(“status”、“ok”、“op”、“getTasks”)被遗漏,只有最后一个与“data”相关的部分被打印(显示)。

4

1 回答 1

1

这个 jsfiddle (jQuery 1.10.1)这个 jsfiddle (jQuery 1.7.2)可能会帮助您入门(区别在于 1.10.1 版本使用Deferred.then()和 1.7.2 版本使用Deferred.pipe().

当我使用延迟/承诺时,我试图寻找的是我已经减少了回调地狱,或者更简单地说,减少了由于嵌套异步回调而引入的嵌套级别。

首先,从识别逻辑功能开始,并将其重构为命名良好的函数,每个函数都返回延迟。

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.logs,并通过一些函数重构,它可以读得更好:

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));
});
于 2013-09-22T11:22:28.483 回答