setInterval获取lastChild异常及加载动效失效问题求助
加载动效异常问题分析与解决
问题现象
- 首行动效失效:第一个加载项的动态三点效果无法显示
- 最后一项状态异常:数组最后一项无法保持结尾带
..!的完成状态
原代码
JavaScript代码
const randomDelay = ()=>{ return new Promise((resolve,reject)=>{ const timeout = (Math.random()*10)%7; setTimeout(() => { resolve(); }, timeout*1000); }); } const addItem = async(item)=>{ let div = document.createElement("div"); div.innerHTML = item; document.body.append(div); await randomDelay(); div.innerHTML = item + "..!"; } async function main() { let t = setInterval(() => { let last = document.body.lastChild; if(last.innerHTML.endsWith("...")){ last.innerHTML = last.innerHTML.slice(0,last.innerHTML.length -3); } else{ last.innerHTML += "."; } }, 300); let items = ["Initializing Hacking", "Reading your files", "Password Files Detected", "Sending all passwords and personal files to server", "Cleaning up"]; // await randomDelay(); for (const item of items) { await addItem(item); } await randomDelay(); clearInterval(t); } console.log("look down here") main();
HTML代码
<!DOCTYPE html> <html> <head></head> <body>top</body> </html>
问题原因
1. 首行动效失效
- 定时器启动后,初始会操作body的第一个子节点(文本节点
top),而第一个加载项的div被添加后,如果randomDelay生成的随机时间小于300ms(定时器首次执行时间),addItem会先将div修改为完成状态,导致定时器还没来得及操作该div,动效就被覆盖。 - 取消注释
await randomDelay()时,main函数会先等待一段随机时间,这段时间定时器持续操作top,等延迟结束后添加第一个div,此时randomDelay的时间足够让定时器多次操作新div,动效得以显示。
2. 最后一项状态异常
- 最后一个
addItem完成并将div设置为..!后,main函数还会执行await randomDelay(),此时定时器仍在运行,会继续修改该div的内容(给..!加.或删减),直到最后清除定时器,导致完成状态被破坏。
修复方案
修复后的JavaScript代码
const randomDelay = ()=>{ return new Promise((resolve)=>{ const timeout = (Math.random()*10)%7; setTimeout(resolve, timeout*1000); }); } const addItem = async(item)=>{ let div = document.createElement("div"); div.innerHTML = item; document.body.append(div); await randomDelay(); div.innerHTML = item + "..!"; return div; } async function main() { let currentDiv = null; let t = setInterval(() => { // 只操作当前加载项的div,跳过已完成状态 if (!currentDiv || currentDiv.innerHTML.includes("..!")) return; if(currentDiv.innerHTML.endsWith("...")){ currentDiv.innerHTML = currentDiv.innerHTML.slice(0, -3); } else { currentDiv.innerHTML += "."; } }, 300); let items = ["Initializing Hacking", "Reading your files", "Password Files Detected", "Sending all passwords and personal files to server", "Cleaning up"]; for (const item of items) { currentDiv = await addItem(item); } await randomDelay(); clearInterval(t); } console.log("look down here") main();
修复点说明
- 跟踪当前加载项:通过
currentDiv变量直接跟踪正在加载的div,避免依赖body.lastChild,彻底解决初始文本节点干扰的问题。 - 跳过已完成状态:定时器回调中判断div是否包含
..!,如果是则跳过操作,保证完成状态不会被修改。 - 返回创建的div:
addItem函数返回创建的div,让main函数精准跟踪每个加载项,逻辑更可靠。
内容的提问来源于stack exchange,提问作者Parth Dave
相关产品推荐
相关产品推荐

