js停止数组遍历+定时器

如下代码,每隔200ms会打印出一组数据,希望能通过一个【停止按钮】来终止打印应该怎么实现?

let str = '12345'
let arr = ['1', '2', '3', '4', '5']
let arr1 = ['a', 'b', 'c', 'd', 'e']
arr.map((item, index1) => {
    return arr1.map((i, index2) => {
        setTimeout(() => {
            console.log(str.replace(item, i))
        }, (index1 * arr1.length + index2) * 1000)
    })
})
阅读 3.2k
4 个回答

在前面加个 变量保存 setTimeout 返回值就好了.

// 加个变量
let stop = false

let str = '12345'
let arr = ['1', '2', '3', '4', '5']
let arr1 = ['a', 'b', 'c', 'd', 'e']
arr.map((item, index1) => {
    return arr1.map((i, index2) => {
        setTimeout(() => {
            // 加个判断
            if(stop) return
            console.log(str.replace(item, i))
        }, (index1 * arr1.length + index2) * 1000)
    })
})

来了来了。注释都补上啦。应该和你需求差不多~

let str = '12345'
let arr = ['1', '2', '3', '4', '5']
let arr1 = ['a', 'b', 'c', 'd', 'e']
let itemArr = []
arr.forEach((str1, index1) => {
    return arr1.forEach((str2, index2) => {
        itemArr.push(str.replace(str1, str2))
    })
})
let id = 0
let index = 0;
const loopFn = () => {
    //达到上限就不要再继续跑啦。
    if (index <= itemArr.length) {
        id = setTimeout(() => {
            console.log(itemArr[index]);
            index++;
            //递归触发
            loopFn()
        }, 200)
    }
}
//开始循环
loopFn()
//按钮点击事件触发这个函数
const clearFn = () => {
    clearTimeout(id);
    index = itemArr.length + 1;// 好像意义不大的 可以删除的
}

题主的代码实际上是设置了无数个 timer,而且一开始就遍历了所有元素,只是慢慢在等各个 timer 执行。
对于这种有规律的行为,使用 setInterval 会更合适一些。

首先用 flatMapmap 生成一个结果集,然后 setInterval 来遍历这个结果集,进行处理。这里只会产生一个 timer,所以很容易用 clearInterval 中止掉

const list = arr.flatMap(i => arr1.map(c => str.replace(i, c)));
const stop = (() => {
    let i = 0;
    let timer = setInterval(() => {
        console.log(list[i++]);

        // 遍历完了就清除定时器
        if (i === list.length) {
            clearInterval(timer);
            timer = 0;
        }
    }, 200);
    return () => clearInterval(timer);
})();

// 1 秒后中断(可以放在按钮事件中)
setTimeout(() => stop(), 1000);

如果不想提交把数据生成好,也要以遍历的过程中来找位置,就类似通过一个全局序号来遍历矩阵。

const count = arr.length * arr1.length;
const stop = (() => {
    let i = 0;
    const stop = () => {
        clearInterval(timer);
        timer = 0;
    };

    let timer = setInterval(() => {
        const value = str.replace(
            arr[Math.floor(i / arr.length)],    // 取整商作为行号
            arr1[i % arr1.length]               // 取余作为列列号
        );
        console.log(value);
        if (++i === count) { stop(); }
    }, 200);

    return stop;
})();


// 1 秒后中断
setTimeout(() => stop(), 10000);

最后还是给一个按题主思路来实现的示例。就是把所有 timer 保存起,停止的时候一个个去停。但是这里需要注意的是,已经完成的 timer,那个序号存在被其他 setTimeout 重用的可能,所以 clearTimeout 的时候存在一点点风险,有可能干掉一个别的 timer。

const timers = arr.flatMap((item, index1) => {
    return arr1.map((i, index2) => setTimeout(
        () => {
            console.log(str.replace(item, i));
        },
        (index1 * arr1.length + index2) * 200)
    );
});

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