1

需求描述-js中睡眠函数的应用场景

  • 最近遇到一个需求,就是需要使用睡眠函数来解决
  • 本篇文章,就简单记录一下吧

什么是睡眠函数

  • js中的所谓的睡眠函数的功能就是
  • 就是让后续代码等一等
  • 自己先睡一会
  • 换句话说,类似于阻塞的功能
  • 请看例子
<button>按钮点击</button>
<script>
    function sleep(time) {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('睡醒了')
            }, time);
        })
    }
    let btn = document.querySelector('button')
    btn.onclick = async () => {
        await sleep(3000)
        console.log('执行某任务');
    }
</script>
  • 上述代码案例中,是按钮点击后,先等待3秒钟
  • 再执行后续的操作(打印任务)
  • 这个东西是有对应的应用场景的
  • 如下:

睡眠函数的应用场景

这里说比较常见的几种场景

  • 使用睡眠函数去优化提升性能
  • 使用睡眠函数去模拟网络延迟的情况
  • 使用睡眠函数去严格控制请求的先后顺序

使用睡眠函数去优化提升性能

  • 比如首页加载,开发项目的时候,来一个sleep(3000)
  • 上线以后,用户反馈首页加载有些慢
  • 于是,进行优化 sleep(2000),收费十万
  • 过段时间,再优化sleep(1000),再次收费十万
  • 手动狗头🐶

使用睡眠函数去模拟网络延迟的情况

  • 这种情况不赘述,就是让某些操作等待一会,sleep(number)
  • 等前面睡醒了,再往后操作
  • 毕竟网络延迟也是类似的情况

使用睡眠函数去严格控制请求的先后顺序

  • 如上图,输入框失去焦点,会发一次请求(输入框可能有多个)
  • 点击按钮又会发一次请求
  • 比如,用户在输入框输入文字内容,再点击按钮
  • 就会发送两个请求(失去焦点事件触发,按钮点击事件触发)
  • 后端要求,必须得保证第一个请求结束以后,再发送第二个请求
  • 这个需求场景,就可以使用sleep睡眠函数来操作
  • 如下完整业务抽离,demo代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.7.2/axios.js"></script>
</head>

<body>
    <input type="text">
    <button>按钮点击</button>
    <script>
        // 两个dom元素
        let input = document.querySelector('input')
        let btn = document.querySelector('button')

        // 是否在发送请求中
        let isSending = false

        // 睡眠函数
        function sleep() {
            return new Promise((resolve) => {
                let timer = setInterval(() => {
                    console.log(isSending ? '请求发送中' : '请求发完了');
                    btn.innerHTML = 'loading...'
                    if (!isSending) {
                        clearInterval(timer)
                        resolve('睡醒了')
                    }
                }, 500);
            })
        }

        // 输入框失去焦点发请求保存数据
        input.onblur = (e) => {
            if(!e.target.value) return
            isSending = true // 请求发送中
            axios.get(`http://ashuai.work/api/op?val=${e.target.value}`).finally(() => {
                isSending = false // 请求发完了
            })
        }

        btn.onclick = async () => {
            await sleep()
            console.log('前一个请求执行完毕,执行下一个请求');
            console.log('下一个请求也执行完毕了');
            btn.innerHTML = '按钮点击'
        }
    </script>
</body>

</html>

效果图如下:

  • 如果这两个请求是独立的,可以直接在第一个请求完成后的.then回调函数中执行第二个请求
  • 但是若两个请求是关联的,就得使用睡眠函数了。
  • 在睡眠函数中,轮询,看看之前的任务是否完成,完成了才‘醒来’。
  • 上述案例是一个请求,我们定义一个标识布尔值变量isSending
  • 若是多个请求,就定义一个task数组,每次发送一个请求,往数组中追加一项
  • 每次每个请求完成后,就数组弹出来一项
  • 等数组为空的时候,就说明任务都完成了,后续代码就可以执行了
  • 即为 ‘睡醒了’

需求描述-控制Tab键在多个输入框中来回切换跳转

需求效果图

v-for循环组件,获取组件的示例ref

循环

<el-input-number v-for="item in scoreArr" ref="inputNumRefs" v-model="item['getScore']" />

语法

  • 获取实例语法
  • ref绑定的值,定义为数组即可
  • 如下
import { ref } from "vue";

// 数组收集多个示例引用
const inputNumRefs = ref([])

console.log('inputNumRefs', inputNumRefs);

这样写的话,inputNumRefs这个变量,会自动收集每个组件的实例,打印图示如下:

然后我们就可以通过inputNumRefs数组的索引,去访问每个组件,进而调用其身上的方法执行了

示例代码

有了这个前置知识,我们就可以看懂下方的示例代码了,建议复制粘贴跑一下,一目了然

<template>
    <h2>左右按Tab键,快速跳转数字输入框(循环)</h2>
    <h3>右手按上下箭头键,快速打分</h3>
    <h4>默认第一个聚焦</h4>
    <div v-for="item in scoreArr">
        <el-input-number step-strictly ref="inputNumRefs" v-model="item['getScore']" :min="0" :max="item['score']"
            :step="0.5" />
        <br>
        <br>
    </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";

const scoreArr = ref([
    {
        "qid": 1111111,
        "qNo": 33,
        "score": 2,
        "getScore": 1
    },
    {
        "qid": 2222222,
        "qNo": 34,
        "score": 2,
        "getScore": 2
    },
    {
        "qid": 3333333,
        "qNo": 35,
        "score": 2,
        "getScore": 2
    },
    {
        "qid": 4444444,
        "qNo": 36,
        "score": 2,
        "getScore": 1.5
    },
])

// 数组收集多个示例引用
const inputNumRefs = ref([])

console.log('inputNumRefs', inputNumRefs);

// 第一个获取焦点的索引
let starIndex = 0

// 调用数字输入框实例去获取焦点
const setFocus = (starIndex: number) => {
    inputNumRefs.value[starIndex].focus()
}

// 监听键盘事件
const handleKeyDown = (event) => {
    if (event.key === 'Tab') {
        event.preventDefault(); // 阻止默认的Tab行为
        starIndex = starIndex + 1 // 索引加一,往下走
        // 若是跳转到最后一项,则回到第一项
        if (starIndex == scoreArr.value.length) starIndex = 0
        // 再执行,去获取焦点
        setFocus(starIndex)
    }
};

// 在组件挂载时添加事件监听
onMounted(() => {
    window.addEventListener('keydown', handleKeyDown);
    // 默认让第一个获取焦点
    setFocus(0)
});

// 组件卸载移除事件监听
onUnmounted(() => {
    window.removeEventListener('keydown', handleKeyDown);
});
</script>
A good memory is better than a bad pen. Write it down...

水冗水孚
1.1k 声望585 粉丝

每一个不曾起舞的日子,都是对生命的辜负