需求描述-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...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。