1

我有一个页面,我在其中触发 ajax 请求并在用户按下按钮后的前 6 秒显示加载标志:

<button onclick="runLoader();"></button>

<script>
    var startTime=(new Date).getTime();
    function runLoader(){
        runAjax();
        var i=0;
        var timer = setInterval(function(e){
            i++;
            //code for loading sign
            if(i==3)
                clearInterval(timer);
        } ,2000);
    }

    function runAjax(){
        $.ajax({
            //
        }).done(function(){
            var timer2 = setInterval(function(){
                var d = new Date();
                var t = d.getTime();
                if(t-startTime>=6000){
                    clearInterval(timer2);
                    // do X
                }
            },500);
        }
    }
</script>

我只想在两者都运行 6 秒并产生响应后才执行操作X ,并且不会更早。runLoader()runAjax()

就像,如果 runAjax() 在 2 秒内响应,我仍然想继续显示加载标志 6 秒,然后执行X。如果加载标志显示了 6 秒,我想等待 runAjax() 返回,只要它需要。

但是使用该Date()方法会给出不准确的结果。例如:即使仅经过 2 秒,它也显示经过了 7.765 秒。我在某个地方读到了我应该使用的地方console.log(time)以获得更好的准确性,但它在 <= IE9 中不起作用。

有没有更好的方法来解决这个问题?

注意:我使用setInterval()而不是setTimeout()因为加载涉及循环通过 3 个元素的数组,“Fetching”、“Processing”和“Loading”每个显示 2 秒 :)

4

3 回答 3

8

我会使用deferreds$.when

function start(){
    $.when(runLoader(), runAjax()).done(function() {
        //both are now finished
    });
}

function runLoader() {
    //show loader here

    var def = $.Deferred();

    setTimeout(function() {
        //hide loader here
        def.resolve(true);
    }, 6000);

    return def.promise();
}

function runAjax() {
    var def = $.Deferred();

    $.ajax({...}).done(function(result) {
        //handle response here
        def.resolve(true);
    });

    return def.promise();
}
于 2013-10-10T13:38:48.477 回答
0

我会设置一个标志将其标记为“准备就绪”。可能有更好的方法来处理这个问题,但这只是我的想法。

<script>
    function runLoader(){
        runAjax();
        var i=0;
        var timer = setInterval(function(e){
            i++;
            //code for loading sign
            if(i==3)
                clearInterval(timer);
        } ,2000);
    }

    function runAjax(){
        var timeElapsed = false;
        setTimeout(function(){timeElapsed = true}, 6000);
        $.ajax({
            //
        }).done(function(){
            var timer2 = setInterval(function(){
                if(timeElapsed){
                    clearInterval(timer2);
                    // do X
                }
            },500);
        }
    }
</script>
于 2013-10-10T13:38:42.283 回答
0

您可以创建一个在 runLoader() 上运行的预调用函数并作为 runAjax() 的回调,它将验证其他操作是否完成,然后执行操作 X。示例:

var ajaxDone = false;
var loaderDone = false;
function doActionX() {
    //your action happens here
}
function tryToDoX() {
    if (ajaxDone && loaderDone) {
        doActionX();
    }
}
function runLoader(){
    loaderDone = false;
    runAjax();
    //show loading sign
    setInterval(function(e){
        //hide loading sign
        clearInterval(timer);
        loaderDone = true;
        tryToDoX();
    }, 6000);
}

function runAjax(){
    ajaxDone = false;
    $.ajax({
        //whatever
    }).done(function(){
        ajaxDone = true;
        tryToDoX();
    }
}

没有必要重复超时并轮询两种状态,因为它们只完成一次(在每次运行中,即布尔值在等待时不会设置为 false 和 true)。

编辑:这种方法可用于任何不会间歇性更改状态的异步代码,即使没有 jQuery。

于 2013-10-10T13:40:02.637 回答