为了账号安全,请及时绑定邮箱和手机立即绑定

js中如何让setInterval倒计时中的alert顺序执行?

js中如何让setInterval倒计时中的alert顺序执行?

关键代码如下:var sec = 10;var t = setInterval(function(){    sec--;    $(".time").html(sec);    if(sec == 0){        alert("游戏结束,你的得分是" + score);        clearInterval(t);    }},1000)当倒计时到最后1秒的时候,会先弹出对话框,此时页面上显示的时间还是1s,等点击确定后才会变成0。我想要的效果是页面上显示倒计时为0的时候显示弹出,而且点击确定后时间不会变成-1,请问怎么实现呢?
查看完整描述

2 回答

?
临摹微笑

TA贡献1982条经验 获得超2个赞

  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 执行了,实际上不是的,执行顺序还是从上往下的,先修改的 DOM 元素的 innerHTML ,然后执行的 alert(),只不过 DOM 元素的 innerHTML 虽然改了,但是页面的渲染并没有进行,因为 js 是单线程的,只有所有的代码执行完了之后,有空闲,才会去渲染页面,实际上题主前面页面的渲染都是在 if 语句执行完后,主线程出现了空闲才进行的。


咱们改个代码,看得更清楚些:


    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,但是实际运行的时候,你会发现,是先 alert 再渲染的 html; 所以题主产生了错觉,innerHTML 延后执行了;


总结:DOM修改是同步的,但是页面的渲染要等主线程空闲;


2、 定时器的**工作机制**

除了主JavaScript 执行进程外,还有一个需要在进程下一次空闲时执行的代码队列;

定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行;

如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行;

在答案里,setTimout(fn,0)仅仅是立马把 fn 添加到了任务队列里,并没有马上执行。


考虑两处代码:


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

alert(2);

alert(3);

此时的主线程和任务队列:


https://img1.sycdn.imooc.com//5c8373ab0001ac8301600127.jpg


队列里的代码等主线程空闲时才会执行,所以 alert(1),会等到alert(2),alert(3)执行完毕后再执行;


alert(1);

alert(2);

alert(3);

此时的主线程和任务队列:


https://img1.sycdn.imooc.com//5c8373ad0001b11701610129.jpg


所以代码按照从上往下的顺序正常执行;


猜测,主线程在执行完代码后,会立马进行渲染,然后再执行任务队列里的代码,既然是队列,代码执行就是从第一个开始到最后一个结束。


所以等代码执行完毕主线程空闲时,首先执行的是渲染,然后执行的 alert();


总结:setTimout 是在指定间隔后,将代码加入任务队列里,等主线程空闲,执行渲染,再依次执行队列里的代码;


所以最前面的代码加上 setTimeout 的作用就在于把代码移到队列里去了,等主线程空闲,页面渲染,再执行 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

查看完整回答
反对 回复 2019-03-09
?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

    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)


查看完整回答
反对 回复 2019-03-09
  • 2 回答
  • 0 关注
  • 717 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信