JavaScript同步Ajax请求特性

时间:2012-03-28 04:15:37

标签: javascript jquery ajax multithreading synchronization

如果我以“怪异”的方式做事,我想以道歉为前言,因为我主要是一名C开发人员,正如我在C中那样解决这个AJAX问题。

我有一个脚本将连接到“推送服务器”,等待消息可用,然后只发送一条消息并断开连接。然后,客户端必须重新建立连接以侦听将来的消息。

我尝试通过在异步回调中实现同步 AJAX调用来实现这一点,除了它出现在DOM之外它可以工作(也许?我在表现出我的无知这里的JS将阻止,直到所有调用完成。

我不知道如何使用纯粹的异步调用来完成它,因为我不希望每次都通过回调调用回调来耗尽堆栈。

这是代码:

        $.ajax({
            url: './recoverDevice',
            data: JSON.stringify(requestData),
            dataType: 'json',
            type: 'POST',
            success: function(j)
            {
                console.log(j);
                if (j.success)
                {
                    //Indefinitely listen for push messages from the server

                    var loopMore = true;
                    while(loopMore)
                    {
                        $.ajax({
                            async: false,
                            url: './getPendingMessage',
                            dataType: 'json',
                            type: 'POST',
                            success: function(j)
                            {
                                //alert(j.message);
                                $("#progressBox").append("<li>" + j.message + "</li>");
                                loopMore = !j.complete;
                            }
                        });
                    }

                }
                else
                {
                    $("#errorBox").show();
                    $("#errorBox").text(j.errorMessage);
                }
            }
        });

现在,从逻辑上讲,此代码工作。在异步函数中,我循环遍历同步 JS调用,每次收到消息时我都会将其附加到DOM,并且只有当服务器告诉我将会我不再发出消息退出循环,结束异步线程并完成任务。

问题是,一旦收到所有消息,DOM访问似乎全部合并。即只有在收到所有消息且异步线程退出后才会发生追加。

注释掉的alert是一个测试 - 它完全 。我在每个通知后都会收到一个消息框,它会正确暂停,直到下一条消息(其余代码为原样)。

我猜这是我的浏览器(Chrome)通过在异步线程退出之前不允许DOM操作来做一些魔法来防止竞争条件?还是我离开了标记并在这里咆哮错误的树?

摆脱循环并将async设置为true会使第一条消息正确接收(没有问题),但显然此后没有消息。

显然我可以这样做:

function GetMessage()
{
    $.ajax({
        async: true,
        url: './getPendingMessage',
        dataType: 'json',
        type: 'POST',
        success: function(j)
        {
            $("#progressBox").append("<li>" + j.message + "</li>");
            if (!j.complete)
            {
                GetMessage();
            }
        }
    });
}

但是这会导致堆栈随着时间的推移而溢出(没有?)。

一个明显的解决方案是在这里也使用异步调用,但是通过某种同步原语发出while循环信号暂停并继续新调用,但看起来JS没有信令原语?

1 个答案:

答案 0 :(得分:0)

想出这个 - 我不知道为什么我之前没有看到这个,但我的后一个代码片段完美无缺。在发布时我没有意识到它,但它不会溢出堆栈,因为每次运行它都会启动异步调用并退出 - 所以堆栈帧永远不会超过2或3深。异步调用是在外部管理的,不会在堆栈中,因此每次重新启动时都会。

我仍然感谢为什么第一种方法(异步调用中的同步代码)没有/不会工作的任何输入。