js动画出现严重掉帧,卡顿,控制台提示类似阻塞的问题

练手做一个小游戏,出问题的部分在

var Attacktimer
function enemyAttack(){
    var speedGroup = new Array();
    var getRandomSpeed = function(){
        for(var i = 0; i < len; i++){
            var Randomspeed = getRandom(4,9);
            speedGroup.push(Randomspeed);
        }
    };
    getRandomSpeed();
    console.log(speedGroup);
    clearInterval(Attacktimer);
    Attacktimer = setInterval(function(){
        for(var j = 0;j<enemyBlock.length;j++){
            num = j;
            enemyBlock[j].style.display = 'block';
            getPower(enemyBlock[j]);
            var newTop = parseInt(enemyBlock[j].style.top);
            enemyBlock[this.num].style.top = newTop + speedGroup[this.num] + 'px';
            if((enemyBlock[j].offsetTop+enemyBlock[j].offsetHeight) >= (playground.offsetTop+playground.offsetHeight-50)){
                enemyBlock[j].style.display = 'none';
            }
            if(enemyBlock[0].style.display === 'none'&&enemyBlock[1].style.display === 'none'&&enemyBlock[2].style.display === 'none'&&enemyBlock[3].style.display === 'none'&&enemyBlock[4].style.display === 'none'&&enemyBlock[5].style.display === 'none'&&enemyBlock[6].style.display === 'none'&&enemyBlock[6].style.display === 'none'){
                    speedGroup = new Array();
                        heightSize = new Array();
                    widthSize = new Array();
                    topArea = new Array();
                    leftArea = new Array();
                    clearInterval(Attacktimer);
            }
                
        }
    },1000/60)
}

定义运动,在控制台看的时候,会严重掉帧,提示的是

if((enemyBlock[j].offsetTop+enemyBlock[j].offsetHeight) >= (playground.offsetTop+playground.offsetHeight-50)){
                enemyBlock[j].style.display = 'none';
            }

控制台提示这一行在进行layout和recalculate时貌似阻塞了。。。。。
之后是再启用了一个新的定时器来反复开启这个

var Autotimer
function playStart(){
    // clearInterval(Autotimer);
    Autotimer = setInterval(function(){
        enemyConfirm();
        enemyAttack();
    },4000)
}

有前辈能看出来大概问题出在哪里吗

阅读 6.5k
2 个回答

1、你的代码里面会不停的触发reflow(如果用的不是fixed或absolute))和repaint
2、 if(enemyBlock[0].style.display === 'none'&&enemyBlock[1].style.display === 'none'&&enemyBlock[2].style.display === 'none'&&enemyBlock[3].style.display === 'none'&&enemyBlock[4].style.display === 'none'&&enemyBlock[5].style.display === 'none'&&enemyBlock[6].style.display === 'none'&&enemyBlock[6].style.display === 'none'){

                speedGroup = new Array();
                    heightSize = new Array();
                widthSize = new Array();
                topArea = new Array();
                leftArea = new Array();
                clearInterval(Attacktimer);
        }

这段代码跟for无关吧?为啥要放到for里面不停的跑,计算要放到for里面跑if里面的值明显可以在外面一次算出来,为啥要每次都去判断取值?
3、playground.offsetTop+playground.offsetHeight-50,这个值也可以在for外面算好吧?
4、不要频繁的setInterval,clearinterval,如果需要做动画可以自己用requestAnimationFrame做一个计时器,计时器本身就是一个极不靠谱的东西,动画一定要跟着主线程的tick走,达不到60fps就用profile工具看哪些函数占用的时间过长,你的关键路径渲染上大部分时间应该都花在paint和composite layer了
5、这种类型的动画尽量用canvas来做,一个层就够了,这种大面积的渲染如果layer过多反而是一个很大的负担
6、计时器可以参考这个我写的这个

立场: 首先你说的问题确实存在
原因: 定时器时间小于js执行时间,从而导致线程被占用,UI层停止绘制
优化办法: 优化办法有很多针对你的问题有大概如下两个办法

  1. 优化自己计算逻辑,比如如上你的代码会引起多次重排,存在很大可优化的点(有实质性效果)

  2. 改用setTimeout(setInterval的话是不管是否js执行完毕都会执行下一次js计算直到某个时间内可以完成某次js计算)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题