鍍金池/ 問答/HTML/ js中如何讓setInterval倒計時中的alert順序執(zhí)行?

js中如何讓setInterval倒計時中的alert順序執(zhí)行?

關鍵代碼如下:

var sec = 10;
var t = setInterval(function(){
    sec--;
    $(".time").html(sec);
    if(sec == 0){
        alert("游戲結束,你的得分是" + score);
        clearInterval(t);
    }
},1000)

當?shù)褂嫊r到最后1秒的時候,會先彈出對話框,此時頁面上顯示的時間還是1s,等點擊確定后才會變成0。
我想要的效果是頁面上顯示倒計時為0的時候顯示彈出,而且點擊確定后時間不會變成-1,請問怎么實現(xiàn)呢?

回答
編輯回答
尛憇藌

圖片描述

2018年2月27日 08:52
編輯回答
撥弦

把sec變量聲明由var sec,改為let sec試試

2017年10月28日 04:56
編輯回答
尛曖昧

這是我的想法,直接復制粘貼運行便可看到效果,希望能幫助到你:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div class="time"></div>
    <script>
        var sec = 4;
        $(".time").html(sec);
        var t = setInterval(function(){
            if(sec == 1){
                clearInterval(t);                
                alert("確認或關閉彈窗變?yōu)?");
                $(".time").html(0);
            } else {
                sec--;
                $(".time").html(sec);
            }
        },1000)
    </script>
</body>
</html>
2018年5月27日 14:03
編輯回答
舊酒館
    var sec = 3;
    var t = setInterval(function() {
        sec--;
        $(".time").html(sec);
        if (sec == 0) {
            setTimeout(function() {
                alert("游戲結束,你的得分是" /*+ score*/ )
            }, 0);
            clearInterval(t);
        }
    }, 1000);

分析:

這個代碼改不難,但是涉及到兩個知識點,題主需要了解下,

1、 修改 innerHTML 與 頁面渲染的問題

題主以為 alert() 先于 innerHTML 執(zhí)行了,實際上不是的,執(zhí)行順序還是從上往下的,先修改的 DOM 元素的 innerHTML ,然后執(zhí)行的 alert(),只不過 DOM 元素的 innerHTML 雖然改了,但是頁面的渲染并沒有進行,因為 js 是單線程的,只有所有的代碼執(zhí)行完了之后,有空閑,才會去渲染頁面,實際上題主前面頁面的渲染都是在 if 語句執(zhí)行完后,主線程出現(xiàn)了空閑才進行的。

咱們改個代碼,看得更清楚些:

    var sec = 3;
    var score = 100;
    var t = setInterval(function() {
        sec--;
        $(".time").html(sec);
        alert("游戲結束,你的得分是" + score);
        if (sec == 0) {
            clearInterval(t);
        }
    }, 1000);

這里每回都會更新頁面和alert(),代碼上先修改的 html,再 alert,但是實際運行的時候,你會發(fā)現(xiàn),是先 alert 再渲染的 html; 所以題主產(chǎn)生了錯覺,innerHTML 延后執(zhí)行了;

總結:DOM修改是同步的,但是頁面的渲染要等主線程空閑;

2、 定時器的**工作機制**
除了主JavaScript 執(zhí)行進程外,還有一個需要在進程下一次空閑時執(zhí)行的代碼隊列;
定時器對隊列的工作方式是,當特定時間過去后將代碼插入。注意,給隊列添加代碼并不意味著對它立刻執(zhí)行,而只能表示它會盡快執(zhí)行;
如果在這個時間點上,隊列中沒有其他東西,那么這段代碼就會被執(zhí)行;

在答案里,setTimout(fn,0)僅僅是立馬把 fn 添加到了任務隊列里,并沒有馬上執(zhí)行。

考慮兩處代碼:

setTimeout('alert(1)',0);
alert(2);
alert(3);

此時的主線程和任務隊列:

clipboard.png

隊列里的代碼等主線程空閑時才會執(zhí)行,所以 alert(1),會等到alert(2),alert(3)執(zhí)行完畢后再執(zhí)行;

alert(1);
alert(2);
alert(3);

此時的主線程和任務隊列:

clipboard.png

所以代碼按照從上往下的順序正常執(zhí)行;

猜測,主線程在執(zhí)行完代碼后,會立馬進行渲染,然后再執(zhí)行任務隊列里的代碼,既然是隊列,代碼執(zhí)行就是從第一個開始到最后一個結束。

所以等代碼執(zhí)行完畢主線程空閑時,首先執(zhí)行的是渲染,然后執(zhí)行的 alert();

總結:setTimout 是在指定間隔后,將代碼加入任務隊列里,等主線程空閑,執(zhí)行渲染,再依次執(zhí)行隊列里的代碼;

所以最前面的代碼加上 setTimeout 的作用就在于把代碼移到隊列里去了,等主線程空閑,頁面渲染,再執(zhí)行 alert();

    var sec = 3;
    var t = setInterval(function() {
        sec--;
        $(".time").html(sec);
        if (sec == 0) {
            setTimeout(function() {
                alert("游戲結束,你的得分是" /*+ score*/ )
            }, 0);
            clearInterval(t);
        }
    }, 1000);

參考資料:
Is innerHTML asynchronous?
When does InnerHTML execute immediately?
How to detect when innerHTML is complete
JavaScript 運行機制詳解:再談Event Loop

2017年11月24日 07:54
編輯回答
懷中人
    var sec = 3; 
    var score = 100;
    var t = setInterval(function(){
        sec--;
        $(".time").html(sec);
        if(sec == 0){
          setTimeout(function(){
            alert("游戲結束,你的得分是" + score);
          },0)
          clearInterval(t);
        }
    },1000)
2018年9月14日 11:16
編輯回答
玩控
var sec = 10;
var t = setInterval(function(){
    sec--;
    if(sec == 0){
        alert("游戲結束,你的得分是" + score);
        clearInterval(t);
    }
    $(".time").html(sec);
},1000)

這樣呢?

2018年8月1日 13:19