Html5游戏中的setInterval与setTimeout

曹洪
• 阅读 1061

在一些特殊的场景中我们可能会需要使用计时器,n秒后执行一段逻辑,或者循环执行一段逻辑。

这个时候我们可能首先想到的会是setInterval()或者setTimeout()两个方法。但是使用这两个方法可能会为我们的工程带来隐患。

记录如下代码片段:

setTimeout(()=>{

    console.log("1")

},0)

console.log("2")

//打印结果

//2

//1

可能会有部分人和我会有同样的疑惑,为什么会先打印2。若有此疑问的同学还需要学习一下js的任务队列和调用栈。

setTimeout传入方法在什么时候执行会变得难以捉摸。所以为解决setTimeout所带来的隐患,需要自己实现相同功能的方法。

这里不考虑浏览器兼容的问题,用requestAnimationFrame来解决setTimeout的问题。

    class Timer{

        constructor(){

            this.lastTime = 0;  //最后一次更新的时间

            this.timeIndex = 0;

            this.timeOutArr = [];   //setTimeout 实例的数组

        }

        update(timestamp){

            if(this.lastTime == 0){

                this.lastTime = timestamp;

            }

            let interval = timestamp - this.lastTime;   //上一帧到当前帧的时间间隔

            this.lastTime = timestamp;  //更新时间

            this.refreshTime(interval); //刷新setTimeout 的时间

        }

        refreshTime(interval){

            let length = this.timeOutArr.length;

            for(let i = length - 1;i>=0;i--){

                let timeOut = this.timeOutArr[i];

                timeOut.time -= interval;   //timeOut实例的剩余时间

                if(timeOut.time <= 16){      //timeOut剩余时间不足1帧 可以立即执行

                    timeOut.func.call(timeOut.thisObj)     //调用回调方法

                    this.timeOutArr.splice(i,1) //移出回调方法

                }

            }

        }

        /**

         * time秒后回调

         * @param fun 要执行的回调方法

         * @param thisObj 执行方法的作用域 避免出错

         * @param time 在time秒后执行回调

         */

        setTimeout(fun,thisObj,time){

            let obj = {

function(){ //外汇常见问题 www.kaifx.cn/lists/question/

                func:fun,

                thisObj:thisObj,

                time:time

            }

            this.timeOutArr.push(obj);

            this.timeIndex++;

        }

    }

    let timer = new Timer();

    function update(timestamp){

        timer.update(timestamp);

        requestAnimationFrame(update)

    }

    requestAnimationFrame(update)

    function test(){

        console.time('timer timeout用时')    

        timer.setTimeout(()=>{

            console.timeEnd('timer timeout用时') //获取setTimeout从创建到执行的时间

        },this,2000)

        console.time('window timeout用时')

        setTimeout(() => {

            console.timeEnd('window timeout用时')

        }, 2000);

        //打印结果

        //windows timeout用时: 2001.82373046875ms

        //timer timeout用时: 2004.0400390625ms

    }

    test();这里简单做了一个timer类,并实现了setTimeout的方法,每一帧都去刷新timer,并记录最后的刷新时间。

对实现的setTimeout方法和window的setTimeout做了个简单的比较,两者从创建到执行所用时间相差不大,经过多次测试window的setTimeout也没有我想象中那么准确。

总结:游戏项目中避免使用window的setTimeout和setInterval方法,若有需要应使用requestAnimationFrame去实现相关方法,将回调控制在了每帧的刷新中。

ps:类似的H5引擎,egret也有自己实现setTimeout方法,想必一方面也是因为浏览器setTimeout存在不确定的因素吧。

点赞
收藏
评论区
推荐文章
Souleigh ✨ Souleigh ✨
4年前
为什么要用 setTimeout 模拟 setInterval ?
在JS事件循环之宏任务和微任务中讲到过,setInterval是一个宏任务。用多了你就会发现它并不是准确无误,极端情况下还会出现一些令人费解的问题。下面我们一一罗列..推入任务队列后的时间不准确定时器代码:setInterval(fn(), N);上面这句代码的意思其实是fn()将会在N秒之后被推入任务队列。所以,在setInterval
Souleigh ✨ Souleigh ✨
4年前
JavaScript 和 Node.js 中事件循环
1.JavaScript中事件循环可以参考《JavaScript忍者秘籍第二版》第十三章,讲解的很好。JavaScript中事件循环,主要就在理解宏任务和微任务这两种异步任务。宏任务(macrotask):setTimeOut、setInterval、setImmediate、I/O、各种callback、UI渲染、messageCh
Karen110 Karen110
3年前
一篇文章带你了解JavaScript时间
一、前言setTimeout(function,milliseconds)在等待指定的毫秒数后执行函数。setInterval(function,milliseconds)setTimeout()相同,但会重复执行。二、时间事件窗口对象允许在指定的时间间隔执行代码。时间间隔称为定时事件。1\.setTimeout()方法window.set
Souleigh ✨ Souleigh ✨
4年前
php为什么不支持定时器?
常见的定时器有两种:一种周期性定时执行,例如每天的凌晨三点出报表;另一种在指定时间后执行(一次),例如会员登录系统五分钟后发放每日登录奖励。两种情况对应shell中的cron和at命令,与JavaScript中的setInterval和setTimeout函数类似(严格来说setInterval是周期性执行,指定时间点执行需要自行处理)。image
Stella981 Stella981
3年前
Mybatis通过Interceptor来简单实现影子表进行动态sql读取和写入
首先进行Mybatis 拦截器介绍    拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法。Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比方,对于Executor,M
Wesley13 Wesley13
3年前
Java多线程之如何创建多线程?
Java与多线程的关系我们平时写的好多简单程序就有多个线程参与,你可能会感到惊讶,但是事实就是这样。Java程序从main()方法开始执行,然后按照既定的代码逻辑执行,看似没有其他线程参与,但实际上Java程序天生就是多线程程序,因为执行main()方法的是一个名称为main的线程。下面我们来用Java的一个管理类验证一下
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
PHP之定时任务(绝对实用)
在工作中经常会用到定时任务,除了在js中有定时器这个玩意可以用于前端页面的定时任务;那么后端PHP如何设置定时任务呢?一.如下是javascript中使用setTimeout和setInterval设置定时任务:1setTimeout(function(){2console.log('timeout');
Wesley13 Wesley13
3年前
JS定时器使用,定时定点,固定时刻,循环执行
本文概述:本文主要介绍通过JS实现定时定点执行,在某一个固定时刻执行某个函数的方法。比如说在下一个整点执行,在每一个整点执行,每隔10分钟定时执行的方法。JavaScript中有两个定时器方法:setTimeout()和setInterval()。这两个方法都可以用来实现在一个固定时间段之后去执行JavaScript。实际上,setTimeout和s
你真的了解@Async吗? | 京东云技术团队
开发中会碰到一些耗时较长或者不需要立即得到执行结果的逻辑,比如消息推送、商品同步等都可以使用异步方法,这时我们可以用到@Async。但是直接使用@Async会有风险,当我们没有指定线程池时,他会默认使用其Spring自带的SimpleAsyncTaskExecutor线程池,会不断的创建线程,当并发大的时候会严重影响性能。所以可以将异步指定线程池使用
京东云开发者 京东云开发者
8个月前
js基础之setTimeout与setInterval原理分析
setTimeout与setInterval概述setTimeout与setInterval是JavaScript引擎提供的两个定时器方法,分别用于函数的延时执行和循环调用。前者的主要思想是通过一个定时器,让函数在计时结束后再执行;后者则是每隔一定的时间,
曹洪
曹洪
Lv1
太过年轻的爱,注定只是一时冲动。
文章
3
粉丝
0
获赞
0