You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

setInterval与setTimeout执行重叠问题排查求助

问题排查:setInterval与setTimeout执行重叠的原因及修复方案

问题根源分析

咱们来一步步拆解你的代码逻辑:在show()函数里,你启动当前div的setInterval逐字符打印后,立刻就递增了cntOuter并设置了下一个setTimeout(show, outerDelay[cntOuter])。这就相当于你提前“预定”了下一个任务的执行时间,完全依赖于你计算的理论时长outerDelay,但这里存在两个核心问题:

  1. 定时器执行并非绝对精准:浏览器的setInterval和setTimeout受事件循环机制影响,实际执行间隔可能和你设置的innerDelayEach有微小偏差,累积下来就会导致理论时长和实际执行时长不匹配。
  2. 未等待当前任务完成就启动下一个:你没有在当前setInterval完全执行完毕(所有字符打印完成、调用clearInterval后)才触发下一个任务,而是提前预定了下一个任务的执行时间。一旦实际执行时长超过理论时长,就会出现多个setInterval同时运行的重叠情况。

另外,你的outerDelay计算逻辑也有漏洞:你假设前一个div的打印时长正好是字符数 * innerDelayEach,但实际中setInterval的每次回调可能因为主线程繁忙被推迟,实际总时长会比理论值长,这也会加剧重叠的概率。

修复方案:基于回调的顺序执行

解决思路很直接:只有当当前div的setInterval完全执行完毕后,再启动下一个div的打印任务,彻底抛弃“提前预定时间”的逻辑,改用任务完成后的回调触发下一个任务。

修改后的完整代码如下:

const data = [
    { "entry": "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness." },
    { "entry": "No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful." },
    { "entry": "Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure." },
    { "entry": "This is a short one." },
    { "entry": "This is line two and it is long" },
    { "entry": "This is line two and it is long" },
    { "entry": "This is line three and it is also long" },
    { "entry": "This is line four and it is very very long" },
    { "entry": "This is line five and it is the longest line of all" },
    { "entry": "This is line six and it is longer than the previous line" },
    { "entry": "B" },
    { "entry": "Who built this country hand by hand, brick by brick. (Applause.) They all came here knowing that what makes somebody an American is not just blood or birth, but allegiance to our founding principles and the faith in the idea that anyone from anywhere can write the next great chapter of our story." }
];

const elmnt = document.querySelectorAll('div');
let cntOuter = 0;
const innerDelayEach = 10;

function show() {
    const select = elmnt[cntOuter];
    let cntInner = 0;
    const text = select.textContent;
    const innerTerminator = text.length - 1;

    const inner = setInterval(function() {
        const val = text[cntInner];
        console.log(cntOuter, cntInner, val);
        cntInner++;

        // 当前div的字符全部打印完成后
        if (cntInner > innerTerminator) {
            clearInterval(inner);
            // 触发下一个div的打印任务
            cntOuter++;
            if (cntOuter < elmnt.length) {
                // 如果需要在两个div之间加延迟,改成 setTimeout(show, 你的延迟值) 即可
                show();
            }
        }
    }, innerDelayEach);
};

show();

关键改动说明

  • 移除了冗余的outerDelay和stringLength数组,不再依赖理论时长计算,而是在当前setInterval结束的回调中直接启动下一个任务
  • 如果需要在两个div的打印流程之间添加自定义延迟,只需要把show()改成setTimeout(show, 你的延迟值)即可
  • 把text和innerTerminator的获取移到了setInterval外部,避免每次回调重复获取DOM内容,提升了性能

这样修改后,每个div的逐字符打印任务都会严格在上一个任务完全结束后才开始,绝对不会出现执行重叠的情况。

内容的提问来源于stack exchange,提问作者smpa01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 14:32:29