动态添加的Promise按顺序执行

原文链接:https://www.cnblogs.com/yalong/p/17935043.html

动态添加的Promise异步事件按顺序执行

需求描述

用户点击一次页面上的一个按钮,就播放一个动画, 如果点击n次就触发n次动画;
在播放动画的同时,如果再点击按钮,那么会把n的次数累加,动画播放也增加对应的次数;
同时支持在动画队列没播放完的时候,可以手动取消后续的动画播放

实现的效果展示

定时器设置为2秒,可以看到不管点击多少次,都是2秒后触发一次,期间可以取消,取消后再点击还是之前的逻辑
因为视频转为gif之后,显示播放的慢了,看打印的时间其实还是2秒的间隔
可以自行复制下面的代码,运行看下效果

代码实现

下面代码中 用setTimeout模拟异步,具体的动画可以放在里面,外面用Promise包裹

<html>
    <style>
        .container {
            border:  1px solid red;
            min-height: 100px;
        }
    </style>
    <body>
        <button id="btn">点我触发事件</button>
        <button id="btn2">点我取消事件</button>
        <button id="btn3">清屏</button>
        <ul class="container">
        </ul>
    </body>
    <script>
        let eventArr = []; //异步事件队列
        let isRunning = false; // 是否正在执行异步事件
        let timerArr = []; // 定时器的数组 用来清除定时器用

        let p = function () {
            return new Promise((resolve, reject) => {
                let t = setTimeout(() => {
                    let d = new Date()
                    let node = document.createElement('li');
                    node.innerHTML = `${eventArr.length + 1} - ${d}`
                    document.querySelector('.container').appendChild(node);
                    resolve(d);
                }, 2000);
                timerArr.push(t);
            });
        }

        document.querySelector('#btn').addEventListener('click', async function(){
            eventArr.push(p);
            if (!isRunning) {
                runner();
            }
        });

        // 取消事件
        document.querySelector('#btn2').addEventListener('click', async function(){
            eventArr = [];
            timerArr.forEach(item => {
                clearTimeout(item);
            });
            timerArr = [];
            isRunning = false;
        });

        // 清屏
        document.querySelector('#btn3').addEventListener('click', async function(){
            document.querySelector('.container').innerHTML = ''
        });

        async function runner (){
            if (eventArr.length) {
                isRunning = true;
                let temp = eventArr.shift();
                await temp();
                timerArr.shift(); // 执行完再去掉
                if (eventArr.length) {
                    runner();
                } else {
                    isRunning = false;
                    return;
                }
            } else {
                isRunning = false;
                return;
            }
        }
    </script>
</html>
posted @ 2023-12-29 15:59  进军的蜗牛  阅读(50)  评论(0编辑  收藏  举报