如果 ajax 花费的时间少于 X 秒,如何延迟显示进度?

Posted

技术标签:

【中文标题】如果 ajax 花费的时间少于 X 秒,如何延迟显示进度?【英文标题】:How to delay showing of progress if ajax takes less than X seconds? 【发布时间】:2016-05-22 19:51:45 【问题描述】:

我在一个页面上有几个 AJAX 调用。有些会立即完成,有些则需要一些时间——这一切都取决于点击的内容。

我想添加一个“加载器”,它会在 AJAX 处理结果时在 X 秒后显示。

我有一个加载器在工作:

   $(document).ajaxStart(function() 
        $("#loader").css("display","block");
    ).ajaxSuccess(function() 
        $("#loader").css("display","none");
    );

这个函数。

但是,当 AJAX 请求很快时,它会在屏幕上闪烁......就像在眨眼之间。除了发生的“闪烁”之外,它效果很好。因此,我试图将加载器 css 更改延迟几秒钟,以便快速结果不会导致“闪烁”。

我已经尝试使用 setTimeout 和 jQuery 队列来延迟事情了。唉:

$(document).ajaxStart(function() 

    $("#loader").queue(function()
        $(this).delay(5000);
        $(this).css("display","block");
        $(this).dequeue();
    );

).ajaxSuccess(function() 
    $("#loader").css("display","none");
);

或:

$(document).ajaxStart(function() 

    setTimeout(function()  
        $("#loader").css("display","block");
    , 5000);

).ajaxSuccess(function() 
    $("#loader").css("display","none");
);

(delaying jquery css changes)

或:

$(document).ajaxStart(function() 
    $("#loader").delay(5000).css("display","block")
).ajaxSuccess(function() 
    $("#loader").css("display","none");
);

但我遇到的问题是,任何在 ajax 启动时延迟 css 更改的尝试通常都会导致延迟......然后负载出现(在 ajax 完成后)。

所以页面加载了 AJAX 数据,然后 5 秒后......加载器出现了。

有没有好办法告诉 ajaxstart() 函数在执行前等待 X 秒?

我不一定想使用类似 onBefore 函数()之类的东西来进行实际 ajax 调用的这一部分,主要是因为某些结果很快返回并且不需要任何进度指示器。通常情况下.. 应该显示进度。 大多数 ajax 请求在 5 秒内完成,只有少数可能需要 10-20 秒。

已经在 ajax 调用中将“加载器”的删除添加到了完整的 function() 中。只是为了确定 ajax 完成后加载器会消失。但是,如果 ajax 在达到任何 setTimeout() 值之前完成,这也会失败(然后加载程序在不应该出现的情况下出现)。

如果 ajax 需要 X 秒或更长时间,我只想对元素进行 css 更改...可以这样做吗?

有没有办法在 AJAX 请求中计时?

【问题讨论】:

编辑了我的答案,应该可以解决你的新问题 优秀~它确实解决了它@JacobGray。 谢谢 【参考方案1】:

setTimeout() 有这个nice feature,您可以在其中获取对超时的引用并取消它。

var ajaxLoadTimeout;
$(document).ajaxStart(function() 
    ajaxLoadTimeout = setTimeout(function()  
        $("#loader").css("display","block");
    , 5000);

).ajaxSuccess(function() 
    clearTimeout(ajaxLoadTimeout);
    $("#loader").css("display","none");
);

这可以防止超时触发,而不是等待它并且在调用完成时什么也不做(如雅各布的回答)。

【讨论】:

我完全忘记了这一点...... +1 以获得很好的答案:D【参考方案2】:

在显示#loader之前检查ajax是否已经完成:

var ajaxDone; //create a global variable called ajaxDone
$(document).ajaxStart(function() 
    ajaxDone = false; //by default, set the ajax as not completed each time the ajax request is sent
    setTimeout(function()  
        if(!ajaxDone) $("#loader").css("display","block");//checks if the ajax has finished yet before displaying #loader
    , 5000);

).ajaxSuccess(function() 
    ajaxDone=true;//When the ajax request finishes, it sets ajaxDone to true
    $("#loader").css("display","none");
);

【讨论】:

我将var = ajaxDone 声明移到了ajaxStart() 函数的内部。这允许加载器在需要的每个请求上显示,而不仅仅是在初始页面请求上。不过做得很好。再次感谢! @SOIA 我可能是错的,但不会在该函数内移动 ajaxDone 使其相对于 only 该函数,这意味着 ajaxDone=true; 将无效? 你是对的。那是个错误。 Chrome 烦人的缓存愚弄了我。那么..我如何让它在初始页面请求之外发挥作用?使用函数外部的 var,只有 1 个请求会显示加载程序,任何第二个或第三个请求都不会。我会把我的编辑放回问题中。谢谢! @SOIA 我删除了我的答案。你说得对。我的错! @gearsdigital 不是问题。我宁愿输入太多也不愿输入不够。 :) 我很感激你的努力!【参考方案3】:

感谢出色的答案,我能够找到解决方案。

我最终希望根据元素 ID 显示一个本地化“加载”图像。全局 ajaxStart()ajaxComplete() 函数不处理本地事件。于是我切换到了beforeSend()函数超时:

 $('.item').click( function (e) 
        e.preventDefault(); 
        var theID = $(this).attr('data');
        var theInfo = $('.holder#h' + theID);
        var loader = $('.waiting#w' + theID);
        $('.holder').slideUp(); //closes any open data holders
        var ajaxLoadTimeout;

        if (!$(theInfo).hasClass('opened')) 
            $(this).addClass('clicked');
            $(theInfo).addClass('opened');
            $(theInfo).html(''); //removes any existing data

        $.ajax(                                      
            url: '_core/inc/getdata.php',  
            type: 'POST',
            data: (dataid: theID),   
            dataType: 'html',

           //shows LOCAL loader before ajax is sent
           //but waits 3 milliseconds before doing so
          //most of the ajax calls take less than 3ms
          //without the timeOut the loader "flashes" for a milisecond
            beforeSend : function() 
                ajaxLoadTimeout = setTimeout(function()  
                $(loader).show();
                , 300);

            ,
            success: function(data) 
                $(theInfo).html(data);

                //Hides LOCAL loader upon ajax success
                clearTimeout(ajaxLoadTimeout);
                $(loader).hide();
            ,
            complete: function()
                    $(theinfo).slideDown();
                
              );

               else 
                $(this).removeClass('clicked');
                $(theInfo).removeClass('opened').slideUp();
            
      );

还有一些相关的 PHP/HTML:

echo '
<h1 class="item" data="'.$this_id.'">'.$this_title.' <span class="waiting" id="w'.$this_id.'"><i class="fa fa-refresh fa-spin fa-lg"></i></span></h1>

<section class="holder" id="h'.$this_id.'"></section>';

CSS:.waiting discplay: none;

我不知道这是对还是错,但它似乎在这里按预期工作。

如果项目的加载时间超过几毫秒,它允许字体真棒图标出现在项目的标题旁边。

【讨论】:

以上是关于如果 ajax 花费的时间少于 X 秒,如何延迟显示进度?的主要内容,如果未能解决你的问题,请参考以下文章

页面加载性能优化

如果没有得到响应,如何在 30 秒后停止 ajax 调用? [复制]

美团性能优化之路——性能指标体系

定时器完成后重启功能

从 Springboard 启动应用程序显着延迟

尝试向 jQuery AJAX 请求添加延迟