在Javascript循环中,是否有可能使浏览器窗口更新?

6
我有一个Ajax调用,目前需要同步执行。然而,在此Ajax调用执行时,浏览器界面会冻结,直到调用返回。在超时的情况下,这可能会导致浏览器冻结相当长的时间
是否有任何方法可以让浏览器(任何浏览器)刷新用户界面,但不执行任何Javascript?理想情况下,它应该是一些命令,例如window.update(),它会让用户界面线程刷新。
如果可能的话,那么我可以用类似以下的代码替换同步Ajax调用:
obj = do_async_ajax_call();
while (!obj.hasReturned()) {
  window.update();
}
// synchronous call can resume

我不能使用setTimeout,或者在回调函数中恢复函数的原因是执行流程不能被中断:(有太多的状态变量都相互依赖,并且long_function()的流程必须以某种方式恢复):
function long_function() {
   // lots of code, reads/writes variable 'a', 'b', ...
   if (sync_call_is_true()) {
     // lots of code, reads/writes variable 'a', 'b', ...
   } else {
     // lots of code, reads/writes variable 'a', 'b', ...
   }
   // lots of code, reads/writes variable 'a', 'b', ...
   return calculated_value;
}

2
为什么调用需要同步? - Frank Schwieterman
1
你能发布完整的调用代码吗?这可能可以简化并使用XHR函数来支持您所需的内容(除非jQuery是一个选项,那么甚至更干净)。如果两者都不是选项,我请求您将函数重命名为do_sync_jax_call(); - Nick Craver
4个回答

3

您需要将同步请求替换为异步请求,并使用回调函数。一个过于简单的例子如下:

obj = do_async_ajax_call(function (data, success)
{
    if (success) 
    {  
        // continue...  
    } 
}); 

function do_async_ajax_call(callback)
{
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://mysite.com", true);
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            callback(xhr.responseXML, true);
        else if (xhr.readyState == 4)
            callback(null, false);
    }
    xhr.send();
}

这样,您将匿名函数作为参数传递给ajax请求函数。 当ajax完成时,传递的函数将被调用,并将responseXML传递给它。 与此同时,浏览器在调用完成之前一直可以自由地执行其通常的操作。从这里开始,您的其余代码将继续执行。

这通常足以满足需要,但我无法分离操作流程(如问题中更新的)。我正在尝试另一种方法... - jevon
将内容翻译为中文:将其分割开始终是可能的;这就是CPS转换(搜索“continuation-passing style”;延续参数就是你的回调函数)。你的本地状态变量只需在回调函数中进行封闭。循环变成递归调用。一旦掌握了这个技巧,它并不难或晦涩难懂。 - Kevin Reid
我同意这种方法总是可行的,但在这种情况下并不是最好的解决方案(因为有太多的状态变量!):) 最终,我使用了之前回调的结果(或定期服务器轮询)来更新客户端,并在必要时使用缓存值来进行同步调用,因此根本不需要调用Ajax。 - jevon

0
将剩余的调用放入回调中,在结果返回时调用该回调。我真的怀疑这对你来说完全不可能。您需要在调用中放置的任何逻辑都可以在回调中复制。

0

使用异步 AJAX 获取数据,然后通过设置延迟时间来分批处理数据(由回调触发)


0

JavaScript是单线程的。因此,根据定义,在紧密循环中无法更新UI。然而,从Firefox 3.5开始,增加了对多线程JavaScript的支持,称为Web Workers。Web Workers不能影响页面的UI,但它们也不会阻止UI的更新。Chrome和Safari也支持Web Workers。
问题是,即使将AJAX调用移动到后台线程并等待执行完成,用户仍然可以按按钮并更改UI上的值(据我所知,这就是您想要避免的)。我唯一能建议的是使用旋转器来防止用户造成任何更改,该旋转器将阻止整个UI,并且在Web调用返回之前不允许与页面进行任何交互。


我不介意用户与页面进行交互(并且交互会排队等待处理);但是当前,在 Firefox 浏览器中执行同步 Ajax 调用时,整个浏览器会冻结。这就是我想要避免的。 - jevon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接