如果我以“奇怪”的方式做事,我想在序言中表达歉意,因为我主要是一名 C 开发人员,并且正在像使用 C 语言一样解决这个 AJAX 问题。
我有一个脚本将连接到“推送服务器”,该脚本会等待消息可用,然后仅发送该消息并中断连接。然后客户端必须重新建立连接以监听 future 的消息。
我尝试通过在异步回调中实现同步 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中。如果没有更多消息,我将退出循环,结束异步线程并完成任务。
问题在于,一旦收到所有消息,DOM 访问似乎就全部合并了。即,仅在收到所有消息并且异步线程退出后才会发生追加。
注释掉的警报
是一个测试 - 它完美工作。我在每次通知后都会收到一个消息框,并且它会正确暂停,直到下一条消息(其余代码按原样)。
我猜这是我的浏览器(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 没有信号原语?
最佳答案
弄清楚了这一点 - 我不知道为什么我之前没有看到这一点,但我的后一个代码片段工作得很好。我在发布时没有意识到这一点,但它不能溢出堆栈,因为每次运行它都会启动异步调用并退出 - 因此堆栈帧的深度永远不会超过 2 或 3。异步调用由外部管理,不会在堆栈上,因此每次都会重新开始。
我仍然希望了解为什么第一个方法(异步调用中的同步代码)不起作用/不起作用的任何意见。
关于JavaScript 同步 Ajax 请求特性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9901060/