-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/>');
           }
       });

これの問題は、非同期であるため、ビュー コントロールのメッセージが順不同で表示されることです。そのため、ajax 内にオプション async:false を配置することにしましたが、これにより、メッセージが順序どおりに表示されているにもかかわらず、Web アプリケーションが完全にブロックされます...悪い考えなので、ajax 呼び出しを処理するキューを実装し、オプション async:false を使用しないことを考えました。私はグーグルで検索し、これを見つけました:

jQuery deferred はどのように使用できますか?

上記ページのコードの下:

/* 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 にブレークポイントを設定し、停止しないため、各タスクを正しくキューに入れていないため、バッファーへの呼び出しが正しくないようです... . それで、私は何を間違っていますか?

最初の試み(Paul Grime の解決策): 私はあなたの解決策を実行しましたが、私ができないことをいくつか変更しようとしています:

1) 私の DoTask は、http コード 200 (タスクが正常に完了した場合) または 500 (タスクが正常に完了しなかった場合) HttpStatusCodeResult(HttpStatusCode.OK)/HttpStatusCodeResult(HttpStatusCode.NotFound) を返します。 ..) doTask の結果を追加したい、例えば:

doTask がタスクを正常に完了した場合:

"結果" : "合格" => 完了 { "結果" : "合格", ...}

doTask がタスクを正しく完了していない場合:

"Result": "Failed" => done { "Result": "Failed", ...}

2) タスクをグループ化したので、最初にタスクの種類を実行するために起動し、それらが終了したら、うまくいくかどうかに関係なく、次の種類のタスクを起動する必要があります。 .. それを行うためにコードを変更する方法は?

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()です。

deferreds/promise を使用しているときに私が探しているのは、コールバックの地獄を減らしたこと、またはより簡単に言えば、ネストされた非同期コールバックの結果として導入されたネストのレベルを減らしたことです。

まず、論理的な機能を特定し、それを適切な名前の関数にリファクタリングして、それぞれが deferred を返すことから始めます。

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 に答える