简体   繁体   中英

About javascript setTimeout asynchronous mode

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        var i = 0;
        var d = 0;
        function BBB() {
            i++;
            alert("11");
            if (i <= 10)
                setTimeout("BBB()", 300);
        }
        function HHH() {
            d++;
            alert("22");
            if (d<= 10)
                setTimeout("HHH()", 300);
        }
        function CCC() {
            BBB();
            HHH();
        }
    </script>
</head>
<body>
    <input type="button" value="Submit" onclick="CCC()"/>
</body>
</html>

I would like to execute BBB function completely,then HHH function. But the result is not so.The output is 11 22 11 11......

How to solve this?Sorry for my poor english! Thanks!

setTimeout causes the functions to not be sequentially executed.

You would do what you do in any other asynchronous context ie

  • Pass the function names as callback names
  • Keep a global variable to keep track
  • Use events.

In your case you have a variable i keeping track of the calls & hence Like this, perhaps :

 <script type="text/javascript">
        var i = 0;
        var d = 0;
        function BBB() {
            i++;
            alert("11");
            if (i <= 10)
                setTimeout("BBB()", 300);
            else HHH();
        }
        function HHH() {
            d++;
            alert("22");
            if (d<= 10)
                setTimeout("HHH()", 300);
        }
        function CCC() {
            BBB();
        }
    </script>

Saw you tagged this with so here is a prettty elegant way to do this using the power of jQuery.

var deferredObj = $.Deferred();
var counter1 = 0;  
var counter2 = 0;  
function First() {
    counter1++;
    alert("first - " + counter1);
    if (counter1 >=3) {
        deferredObj.resolve();
        return;
    }
    setTimeout(First, 300);
}

function Second() {
    counter2++;
    alert("second - " + counter2);
    if (counter2 >= 3)
        return;
    setTimeout(Second, 300);
}

First();
deferredObj.done(function(){
    Second();
});

The key here is marking the deferred object as "resolved" when first method finish, then jQuery knows it can execute the second method. Credits for this way belong to Kevin in this answer .

Live test case .

An optimized version of a function that runs a set of functions in their order.

var runner = function(fn) {
    var counter = 10, delay = 300;
    setTimeout(function run(){
        fn[0].apply(this);
        counter--;
        counter && setTimeout(run, delay);
        !counter && fn.shift() && fn.length && runner(fn);
    }, delay);
};

You can use it as follows:

var log = function(text){
    return function(){
        console.log(text);
    };
};

runner([ log("1"), log("2"), log("3") ]);

A live example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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