如何每隔2秒向DOM指定坐标添加图片且避免页面加载阻塞
问题描述
给朋友制作生日快乐主题网站时,需要实现每隔2秒在指定坐标位置向DOM中添加气球图片元素的效果,最初编写了单次触发的定时逻辑和气球创建函数:
单次定时调用代码:
setTimeout(function(){ createBalloon(); }, 2000);
气球创建函数实现:
function createBalloon() { var colors = ["10vw","30vw","50vw","70vw", "90vw"]; var randColor = colors[Math.floor(Math.random() * colors.length)]; var img = document.createElement("img"); img.src = "balloon.jpg"; img.className = "balloon"; var div = document.getElementById("balloon-div"); div.appendChild(img); img.style.position = "absolute"; img.style.top = "100vh"; img.style.left = randColor; var balloonList = document.getElementsByClassName("balloon"); }
将上述setTimeout放入无限循环尝试实现周期调用时,页面直接无法正常加载。
故障原因
不要用手写while(true)这类无限循环包裹定时逻辑。JavaScript是单线程运行的,这类死循环会持续占满主线程调用栈,浏览器既没有机会执行定时回调,也无法完成页面渲染,直接就会卡死。周期执行的需求不需要自己写无限循环,调用浏览器原生提供的定时API就能实现。
正确实现方案
两种常用实现方式,按需选择即可:
- 方案一:用
setInterval实现固定间隔调用setInterval本身就会按照指定时间间隔循环执行传入的回调,不需要额外编写循环逻辑:
// 等DOM加载完成后再启动定时器,避免找不到balloon-div元素报错 window.addEventListener('load', function() { // 每隔2000毫秒执行一次气球创建函数 setInterval(createBalloon, 2000); })
如果后续需要停止生成气球,只要把setInterval的返回值存到变量里,调用clearInterval(存的返回值)就能终止定时任务。
- 方案二:递归调用
setTimeout(扩展性更好)
如果后续要加扩展逻辑,比如随机生成间隔、页面上气球太多时暂停生成,可以在createBalloon函数执行末尾递归调用setTimeout,灵活性更高:
function createBalloon() { var colors = ["10vw","30vw","50vw","70vw", "90vw"]; var randColor = colors[Math.floor(Math.random() * colors.length)]; var img = document.createElement("img"); img.src = "balloon.jpg"; img.className = "balloon"; var div = document.getElementById("balloon-div"); div.appendChild(img); img.style.position = "absolute"; img.style.top = "100vh"; img.style.left = randColor; var balloonList = document.getElementsByClassName("balloon"); // 本次气球创建完成后,间隔2秒再创建下一个 setTimeout(createBalloon, 2000); } // 页面加载完成后触发第一次创建即可 window.addEventListener('load', function() { setTimeout(createBalloon, 2000); })
小提示:一定要等DOM加载完成后再启动定时逻辑,否则代码执行时
balloon-div还没渲染出来,getElementById会拿不到元素报错。
内容的提问来源于stack exchange,提问作者Prakhar Parikh
相关产品推荐
相关产品推荐

