web面试题
本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-)
web面试题专栏:点击此处
场景分析
移动端web页面,需要实现滚动加载,如果一直监听滚动事件,触发滚动事件,则向后端发送数据请求。
节流的原理
限制单位时间内可以执行操作的次数。
一开始,只要触发了,就开始计时,在单位时间内,无论再次触发也不会执行操作,只有等到单位时间结束,执行了操作,才会开始新的一轮。
就以鼠标在div上移动,实时监听坐标信息,延迟500毫秒为例子。
监听移动事件是一直在运行的。
最初,开始监听移动事件,第一次触发了滚动事件,就会进入500毫秒的计时,在这500毫秒内,无法再怎么移动,都不会打印坐标信息;等到了500毫秒结束后,才会打印坐标信息。然后监听移动事件又开始新的一轮...
节流的实现
这里只做部分代码的抽取,源码在最后面,可运行的HTML文件。
1. 不做节流的例子
这里不做节流,方便对比~
// dom
<div class="throttle_box">
<span class="throttle_box_label">不做节流:</span>
<div id="moveBox1" class="moveBox"></div>
</div>
// js
var moveBox1 = document.getElementById("moveBox1");
moveBox1.addEventListener("mousemove", function (e) {
console.log(`不做节流:e.screenX:${e.screenX}`);
});
2. 全局标志位isRunning做节流的例子
这里用isRunning来判断是否当前是否在运行中,是的话,就要运行结束,下次触发才生效。
思考1:如果有多个需求要节流处理,是不是有好多个isRunningX变量?要怎么封装才好呢?
思考2:另外,业务跟功能夹杂在一起了,能不能抽取出节流这个功能呢?
注意:打印事件对象e!!! 闭包不能直接获取到~
// dom
<div class="throttle_box">
<span class="throttle_box_label">全局标志位isRunning实现节流:</span>
<div id="moveBox2" class="moveBox"></div>
</div>
// 标志位,判断是否运行中...
// 如果是在运行了,则跳过业务逻辑;
// 如果不在运行,则将状态改成在运行中,并且在业务逻辑处理完毕后,需要将状态改成不在运行中...
let isRunning = false;
var moveBox2 = document.getElementById("moveBox2");
moveBox2.addEventListener("mousemove", function (e) {
// 不在运行中
if (!isRunning) {
setTimeout(() => {
console.log(`全局标志位isRunning实现节流:e.screenX:${e.screenX}`);
// 运行完毕需要关闭正在运行的标志
isRunning = false;
}, 500);
isRunning = true;
}
});
3. 闭包做节流的例子
这个东西比较难理解,不懂的同学可以先看看闭包~
注意1:this的作用域问题,需要用call来处理
注意2:事件e要怎么在闭包中传递
// dom
<div class="throttle_box">
<span class="throttle_box_label">闭包实现节流:</span>
<div id="moveBox3" class="moveBox"></div>
</div>
// js
var moveBox3 = document.getElementById("moveBox3");
moveBox3.addEventListener(
"mousemove",
// 改参数是一个函数
// 应用闭包,返回的函数自带作用域私有变量
throttle((e) => {
console.log(`闭包实现节流 input3:e.screenX:${e.screenX}`);
}, 500)
);
/**
* @author: Penk
* @description: 节流函数
* @param {*} fn
* @param {*} timeout
* @return {*}
*/
function throttle(fn, timeout = 500) {
let isRunning = false;
// 这里的event,可以通过.call 传过去到fn参数中
return function (e) {
if (!isRunning) {
setTimeout(() => {
fn.call(this, e);
isRunning = false;
}, timeout);
isRunning = true;
}
};
}
源码
<!--
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2022-11-23 02:28:41
* @FilePath: \web面试题\节流.html
* @email: 492934056@qq.com
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 100%;
height: 100vh;
padding: 20px;
box-sizing: border-box;
}
.moveBox {
width: 500px;
height: 200px;
background-color: antiquewhite;
}
.throttle_box .throttle_box_label {
display: block;
margin: 30px 0 10px 0;
}
.tooltips {
display: block;
color: red;
font-size: 12px;
margin-top: 2px;
}
</style>
</head>
<body>
<h3>这边制作的是一个div,监听器鼠标在div上滑动然后就调用异步方法。</h3>
<div class="throttle_box">
<span class="throttle_box_label">不做节流:</span>
<div id="moveBox1" class="moveBox"></div>
</div>
<div class="throttle_box">
<span class="throttle_box_label">全局标志位isRunning实现节流:</span>
<div id="moveBox2" class="moveBox"></div>
</div>
<div class="throttle_box">
<span class="throttle_box_label">闭包实现节流:</span>
<div id="moveBox3" class="moveBox"></div>
</div>
<div class="throttle_box">
<span class="throttle_box_label">闭包实现节流:</span>
<div id="moveBox4" class="moveBox"></div>
</div>
<script>
var moveBox1 = document.getElementById("moveBox1");
moveBox1.addEventListener("mousemove", function (e) {
console.log(`不做节流:e.screenX:${e.screenX}`);
});
// 标志位,判断是否运行中...
// 如果是在运行了,则跳过业务逻辑;
// 如果不在运行,则将状态改成在运行中,并且在业务逻辑处理完毕后,需要将状态改成不在运行中...
let isRunning = false;
var moveBox2 = document.getElementById("moveBox2");
moveBox2.addEventListener("mousemove", function (e) {
// 不在运行中
if (!isRunning) {
setTimeout(() => {
console.log(`全局标志位isRunning实现节流:e.screenX:${e.screenX}`);
// 运行完毕需要关闭正在运行的标志
isRunning = false;
}, 500);
isRunning = true;
}
});
var moveBox3 = document.getElementById("moveBox3");
moveBox3.addEventListener(
"mousemove",
// 改参数是一个函数
// 应用闭包,返回的函数自带作用域私有变量
throttle((e) => {
console.log(`闭包实现节流 input3:e.screenX:${e.screenX}`);
}, 500)
);
var moveBox4 = document.getElementById("moveBox4");
moveBox4.addEventListener(
"mousemove",
// 改参数是一个函数
// 应用闭包,返回的函数自带作用域私有变量
// 这里的e,不是事件监听直接给的,是由闭包call带参e
throttle((e) => {
console.log(`闭包实现节流 input4:e.screenX:${e.screenX}`);
}, 500)
);
/**
* @author: Penk
* @description: 节流函数
* @param {*} fn
* @param {*} timeout
* @return {*}
*/
function throttle(fn, timeout = 500) {
let isRunning = false;
// 这里的event,可以通过.call 传过去到fn参数中
return function (e) {
if (!isRunning) {
setTimeout(() => {
fn.call(this, e);
isRunning = false;
}, timeout);
isRunning = true;
}
};
}
</script>
</body>
</html>
源码页面展示图
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/66359.html