简体   繁体   English

JavaScript同步Ajax请求特质

[英]JavaScript Synchronous Ajax Request Idiosyncrasies

I'd like to preface this with an apology if I'm doing things in a "weird" way, as I'm primarily a C developer and am solving this AJAX problem the way I would in C. 如果我以“怪异”的方式做事,我想为此道歉,因为我主要是C开发人员,并且正在以与C中相同的方式解决AJAX问题。

I have a script that will be connecting to a "push server" that waits until a message is available, then sends only that one message and breaks the connection. 我有一个脚本,该脚本将连接到“推送服务器”,该脚本将等待消息可用,然后仅发送该一条消息并断开连接。 The client must then reestablish the connection to listen for future messages. 然后,客户端必须重新建立连接以侦听将来的消息。

I tried to do this by implementing a synchronous AJAX call within an asynchronous callback, and it works except it appears the DOM (maybe? I'm showing my ignorance of JS here) will block until all calls are complete. 我试图通过在异步回调中实现同步 AJAX调用来做到这一点,并且它工作正常,但它似乎会阻止DOM(也许是吗?我在这里展示了我对JS的无知)会阻塞,直到所有调用都完成为止。

I do not know how to do it with purely asynchronous calls as I do not want to end up exhausting the stack by having a callback calling a callback each time. 我不知道如何使用纯异步调用来完成此操作,因为我不想每次都有一个调用回调的回调而最终耗尽堆栈。

This is the code: 这是代码:

        $.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);
                }
            }
        });

Now, logically, this code should work. 现在,从逻辑上讲,此代码应该可以正常工作。 Within an asynchronous function, I loop over a synchronous JS call, each time I get a message I will append it to the DOM, and only when the server tells me there will be no more messages do I exit the loop, ending the asynchronous thread and completing the task. 异步函数中,我遍历一个同步 JS调用,每次收到一条消息时,我都会将其附加到DOM,只有当服务器告诉我不再有消息时,我才退出循环,结束异步线程并完成任务。

The problem is that the DOM access appears to be all coalesced once all messages have been received. 问题在于,一旦收到所有消息,DOM访问似乎就全部合并了。 ie the appends only happen once all messages have been received and the asynchronous thread has exited. 即,仅当接收到所有消息并且退出异步线程后,才执行附加操作。

The commented out alert was a test - it works perfectly . 注释掉的alert是一个测试-效果很好 I get a message box after each and every notification, and it pauses correctly until the next message (with the rest of the code as-is). 在每条通知之后,我都会看到一个消息框,它会正确暂停,直到出现下一条消息为止(其余代码保持原样)。

I'm guessing this is my browser (Chrome) doing some magic to protect against race conditions by not allowing DOM manipulation until the asynchronous thread has exited? 我猜想这是我的浏览器(Chrome)通过禁止在异步线程退出之前才允许DOM操作来保护自己免受竞争情况的魔力吗? Or am I way off the mark and barking up the wrong tree here? 还是我偏离常规,在这里吠错了树?

Getting rid of the loop and setting async to true makes the first message be received properly (no problems there), but obviously no messages thereafter. 摆脱循环并将async设置为true可以正确接收第一个消息(那里没有问题),但是此后显然没有消息。

Obviously I could do something like this: 显然我可以做这样的事情:

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

But that would result in a stack overflow over time (no?). 但是,随着时间的推移,这会导致堆栈溢出(不是吗?)。

An obvious solution would be to use asynchronous calls here too, but to signal a while loop to pause and continue with new calls via some sort of synchronization primitives, but appears that JS does not have signalling primitives? 一个明显的解决方案是也可以在此处使用异步调用,但是通过某种同步原语来发信号通知while循环暂停并继续进行新的调用,但是看起来JS没有信令原语?

Figured this one out - I don't know why I didn't see this before but my latter code fragment works perfectly. 想通了这一点-我不知道为什么以前没有看到这个,但是我后面的代码片段可以完美地工作。 I didn't realize it at the time of posting, but it can't overflow the stack because each time it runs it launches an async call and exits - so the stack frame is never more than 2 or 3 deep. 在发布时我还没有意识到,但是它不会溢出堆栈,因为每次运行它都会启动一个异步调用并退出-因此堆栈框架的深度永远不会超过2或3。 The asynchronous calls are managed externally and won't be on the stack, so each time it starts over. 异步调用是从外部管理的,并且不会在堆栈上,因此每次重新启动时都如此。

I'd still appreciate any input on why the first method (synchronous code in asynchronous call) didn't/wouldn't work. 对于第一个方法(异步调用中的同步代码)为何不起作用/为何不起作用的任何输入,我仍然将不胜感激。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM