4

我有多个需要串联调用的进程(我正在使用同步 AJAX 调用)。我想在完成后显示一个长时间运行的进程的状态,然后继续下一个。这是我编写的示例代码。

    var counter = 0;
function runProcess(input, output) {
    doWork();
    doWork();
    doWork();
};
function doWork() {
    counter++;
    document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Running " + counter;

    // some lengthy calculations
    for (var i = 0; i < 1000000; i++) {
        var foo = Math.random();
    }
    setTimeout(updateStatus, 1000);
};
function updateStatus() {
    document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Done " + counter;
}

当我运行它时,我得到以下响应:

运行 1运行 2运行 3完成 3完成 3完成 3

我想得到

运行 1 完成 1 运行 2 完成 2 运行 3 完成 3

如果我在 updateStatus 函数中插入一个 alert() 语句,那么我会得到我想要的响应/执行顺序。浏览器是否为 3 个函数调用创建 3 个线程并异步执行它们?

我怎样才能连续运行它?setTimeout 是否正确实施?提前感谢您的帮助。

4

3 回答 3

2

听起来您想将 AJAX 调用排队。jQuery 提供了一个很好的队列函数,因此您可以确保一系列函数被一个接一个地调用。Mootools 和其他框架提供了类似的功能。

这是我的小提琴中的代码,显示了如何做到这一点。

var queueElement = $("#output");
var counter = 0;

function doWork(next) {
    queueElement.append("Starting " + counter + "<br/>");
    counter++;
    $.ajax('/echo/json/').always(function() {
        queueElement.append("Ending " + counter + "<br/>");
        next();
    });
}

queueElement.queue('workQueue', doWork);
queueElement.queue('workQueue', doWork);
queueElement.queue('workQueue', doWork);
queueElement.dequeue('workQueue'); // start the work queue
于 2012-11-11T01:11:02.810 回答
0

关于浏览器中的 Javascript,您必须了解的一件事是它是单线程的。当您更改 DOM 时,屏幕不会更改,直到您的脚本放弃控制。

这是两次调用 doWork() 时的真实事件序列:

  1. 称呼doWork()
  2. doWork()添加运行消息
  3. 排队等待updateStatus()稍后执行
  4. doWork()再打电话
  5. doWork()添加运行消息
  6. 排队等待updateStatus()稍后执行
  7. runProcess()退出并将控制权返回给浏览器
  8. 浏览器使用正在运行的消息更新屏幕
  9. 第一个updateStatus()电话被打了。完成后,屏幕更新
  10. 第二次updateStatus()调用。完成后,屏幕更新

您可以通过完全不打乱电话来获得您想要的东西updateStatus(),只需从内部打印出您完成的消息doWork()

于 2012-11-09T21:52:27.493 回答
0

队列很好用。在需要连续调用的 $.ajax 方法上使用队列效果很好。如果我在不使用队列的情况下使用“async: false”选项,则 UI 只会在所有长时间运行的进程完成后才会刷新。

感谢您为我指明正确的方向!如果有人在看,这是我的最终代码:

function callService(url, workflowid, modelid, next) {
        var jData = {};
        jData.workflowid = workflowid;
        jData.modelid = modelid;
        //alert(JSON.stringify(jData));
        $.ajax({
            url: url,
            type: "POST",
            dataType: "json",
            contentType: "application/json; charset=utf-8;",
            async: true,
            cache: false,
            data: JSON.stringify(jData),
            success: function (oResult) {
                $("#Message").append("&nbsp;&nbsp;" + oResult.Message);
                if (!oResult.Success) {
                    $("#<%:this.FailureText.ClientID %>").append("&nbsp;&nbsp;" + oResult.Error);
                } else { next(); }
            },
            error: function (exc) {
                $("#Message").append("&nbsp;&nbsp;" + exc.responseText);
            }
        });
    }
    function runServices() {
        var queueElement = $("#q");
        var queueStatus = $("#Message");

        queueStatus.append("<br/>Starting workflows at : " + new Date() + "<br/>");
        var list = $(":input:checkbox:checked"); // getting all selected checkboxes.
        $(list.each(function () {
            var workflowid = $(this).val();
            queueElement.queue("WorkflowQ", function (next) {
                callService("/Services/Workflow.svc/rest/runworkflow", workflowid, document.getElementById('<%=this.MODELID.ClientID%>').value, next);
            });
        }));          
        queueElement.dequeue("WorkflowQ");
    };

    <input type="button" id="ExecuteButton" value="Execute Workflow" class="button" onclick="runServices();"/>

<div id="Message"></div>
<div id="q"></div>
于 2012-11-12T19:14:49.347 回答