开发者

Long task in Javascript

Why in the following code I see the whole page at once ? Th开发者_如何学Canks !

HTML:

<div></div>

CSS:

div {
    width: 100px;
    height: 300px;
    border: 1px solid black;
    text-align: center;
}

Javascript:

$(function() {
    for (var i=0; i<15; i++) {
        sleep(100);
        $("div").append("<span>--- " + i + " ---<br /></span>");
    }

    function sleep(milliseconds) {
        var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
            if ((new Date().getTime() - start) > milliseconds){
                break;
            }
        }
    }
});


Because Javascript on web browsers is single-threaded (although that's changing; see below) and virtually no browser updates its UI while the (main) Javascript thread is busy. All your sleep function does is block everything for 100ms, it doesn't let the browser do anything else like update its UI (e.g., doesn't "yield").

There are a couple of ways to do what you're trying to do:

  1. Use the new web workers stuff; but note that it's not widely-supported yet.

  2. Make your loop a function that calls itself via setTimeout. That way, your code is yielding to the browser and letting it update its UI.

Here's a simple example of how you might apply #2 above to your code:

$(function() {
    var i;

    doOne();

    function doOne() {
        $("div").append("<span>--- " + i + " ---<br /></span>");
        if (i++ < 15) {
            setTimeout(doOne, 0);   // <== Won't really be zero, browsers clamp it at ~10
        }
    }

});

If you have a lot of loop iterations (e.g., a couple of hundred instead of 15), it may well be worth doing a chunk of them on each iteration rather than yielding on each iteration; the yield takes a measureable time (typically ~10-15ms).


You need to hand over some processing time to the UI since javascript is single threaded, like this:

$(function() {
    function appendDiv(i) {
        $("div").append("<span>--- " + i + " ---<br /></span>");
        if(i < 14) 
            setTimeout(function() { appendDiv(i+1); }, 100);  
    }
    appendDiv(0);
});​

You can see a demo here

You could also use an interval for what you want, like this:

$(function() {
    var i = 0;
    var interval = setInterval(function() {
        $("div").append("<span>--- " + i++ + " ---<br /></span>");
        if(i == 15) clearInterval(interval);
    }, 100);
});​
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜