手写题之防抖节流!
防抖_基本实现
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.4/underscore-umd-min.js"></script>
<script>
function mjdebounce(fn, delay) {
let timer = null
const _debounce = () => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn()
timer = null
}, delay)
}
return _debounce
}
</script>
<script>
const inputEl = document.querySelector("input")
let counter = 1
inputEl.oninput = mjdebounce(function() {
console.log(`发送网络请求${counter++}`, this)
}, 1000)
</script>
</body>
</html>
防抖_this和参数的绑定
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<script>
function mjdebounce(fn, delay) {
let timer = null
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
return _debounce
}
</script>
<script>
const inputEl = document.querySelector("input")
let counter = 1
inputEl.oninput = mjdebounce(function(event) {
console.log(`发送网络请求${counter++}`, this.value, event)
}, 1000)
</script>
</body>
</html>
防抖_取消功能
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<button class="cancelBtn">取消</button>
<script>
function mjdebounce(fn, delay) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
isInvoke = false
}, delay);
}
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
}
return _debounce
}
</script>
<script>
const inputEl = document.querySelector("input")
const cancelBtn = document.querySelector(".cancelBtn")
let counter = 1
const debounceFn = mjdebounce(function(event) {
console.log(`发送网络请求${counter++}`, this.value, event)
}, 3000)
inputEl.oninput = debounceFn
cancelBtn.onclick = function() {
console.log('取消');
debounceFn.cancel()
}
</script>
</body>
</html>
防抖_立即执行
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<button class="cancelBtn">取消</button>
<script>
function mjdebounce(fn, delay, immediate = false) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
return
}
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
isInvoke = false
}, delay);
}
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
}
return _debounce
}
</script>
<script>
const inputEl = document.querySelector("input")
const cancelBtn = document.querySelector(".cancelBtn")
let counter = 1
const debounceFn = mjdebounce(function(event) {
console.log(`发送网络请求${counter++}`, this.value, event)
}, 3000, true)
inputEl.oninput = debounceFn
cancelBtn.onclick = function() {
console.log('取消');
debounceFn.cancel()
}
</script>
</body>
</html>
防抖_返回值
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<button class="cancel">取消</button>
<script>
function mjdebounce(fn, delay, immediate = false, resultCallback) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
return new Promise((resolve, reject) => {
try {
if (timer) clearTimeout(timer)
let res = undefined
if (immediate && !isInvoke) {
res = fn.apply(this, args)
if (resultCallback) resultCallback(res)
resolve(res)
isInvoke = true
return
}
timer = setTimeout(() => {
res = fn.apply(this, args)
if (resultCallback) resultCallback(res)
resolve(res)
timer = null
isInvoke = false
}, delay);
} catch (error) {
reject(error)
}
})
}
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
</script>
<script>
const inputEl = document.querySelector("input")
const cancelBtn = document.querySelector(".cancel")
const myDebounceFn = mjdebounce(function(name, age, height) {
console.log("----------", name, age, height)
return "codermjjh 哈哈哈哈"
}, 1000, false)
myDebounceFn("mjjh", 18, 1.88).then(res => {
console.log("拿到执行结果:", res)
})
</script>
</body>
</html>
防抖_最终代码
function mjdebounce(fn, delay, immediate = false) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
return new Promise((resolve, reject) => {
try {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
res = fn.apply(this, args)
resolve(res)
isInvoke = true
return
}
timer = setTimeout(() => {
res = fn.apply(this, args)
resolve(res)
timer = null
isInvoke = false
}, delay);
} catch (error) {
reject(error)
}
})
}
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
export default mjdebounce
节流
节流_基本实现
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<script>
function mjthrottle(fn, interval) {
let startTime = 0
const _throttle = function() {
const nowTime = new Date().getTime()
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
fn()
startTime = nowTime
}
}
return _throttle
}
</script>
<script>
const inputEl = document.querySelector("input")
let counter = 1
inputEl.oninput = mjthrottle(function() {
console.log(`发送网络请求${counter++}:`, this.value)
}, 1000)
</script>
</body>
</html>
节流_this和参数的绑定
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<script>
function mjthrottle(fn, interval) {
let startTime = 0
const _throttle = function(...args) {
const nowTime = new Date().getTime()
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
fn.apply(this, args)
startTime = nowTime
}
}
return _throttle
}
</script>
<script>
const inputEl = document.querySelector("input")
let counter = 1
inputEl.oninput = mjthrottle(function() {
console.log(`发送网络请求${counter++}:`, this.value)
}, 1000)
</script>
</body>
</html>
节流_立即执行 尾部执行
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<script>
function mjthrottle(fn, interval, {
leading = true,
trailing = false
} = {}) {
let startTime = 0
let timer = null
const _throttle = function(...args) {
const nowTime = new Date().getTime()
if (!leading && startTime === 0) {
startTime = nowTime
}
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
if (timer) clearTimeout(timer)
fn.apply(this, args)
startTime = nowTime
timer = null
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
fn.apply(this, args)
startTime = new Date().getTime()
timer = null
}, waitTime);
}
}
return _throttle
}
</script>
<script>
const inputEl = document.querySelector("input")
let counter = 1
inputEl.oninput = mjthrottle(function() {
console.log(`发送网络请求${counter++}:`, this.value)
}, 3000, {
trailing: true
})
</script>
</body>
</html>
节流_取消功能
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<button class="cancel">取消</button>
<script>
function mjthrottle(fn, interval, {
leading = true,
trailing = false
} = {}) {
let startTime = 0
let timer = null
const _throttle = function(...args) {
return new Promise((resovle, reject) => {
try {
const nowTime = new Date().getTime()
if (!leading && startTime === 0) startTime = nowTime
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
if (timer) clearTimeout(timer)
res = fn.apply(this, args)
resovle(res)
startTime = nowTime
timer = null
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
res = fn.apply(this, args)
resovle(res)
startTime = new Date().getTime()
timer = null
}, waitTime)
}
} catch (error) {
reject(error)
}
})
}
_throttle.cancel = function() {
if (timer) clearTimeout(timer)
startTime = 0
timer = null
}
return _throttle
}
</script>
<script>
const inputEl = document.querySelector("input")
const cancelBtn = document.querySelector(".cancel")
let counter = 1
const throttleFn = mjthrottle(function() {
console.log(`发送网络请求${counter++}:`, this.value)
}, 3000, {
trailing: true
})
throttleFn("aaaa")
</script>
</body>
</html>
节流_返回值
<!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>
</head>
<body>
<button>按钮</button>
<input type="text">
<button class="cancel">取消</button>
<script>
function mjthrottle(fn, interval, {
leading = true,
trailing = false
} = {}) {
let startTime = 0
let timer = null
const _throttle = function(...args) {
return new Promise((resovle, reject) => {
try {
const nowTime = new Date().getTime()
if (!leading && startTime === 0) startTime = nowTime
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
if (timer) clearTimeout(timer)
const res = fn.apply(this, args)
resovle(res)
startTime = nowTime
timer = null
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
const res = fn.apply(this, args)
resovle(res)
startTime = new Date().getTime()
timer = null
}, waitTime)
}
} catch (error) {
reject(error)
}
})
}
_throttle.cancel = function() {
if (timer) clearTimeout(timer)
startTime = 0
timer = null
}
return _throttle
}
</script>
<script>
const inputEl = document.querySelector("input")
const cancelBtn = document.querySelector(".cancel")
let counter = 1
const throttleFn = mjthrottle(function() {
return "return value"
}, 3000, {
trailing: true
})
throttleFn("aaaa").then(res => {
console.log(res);
})
</script>
</body>
</html>
节流_最终代码
function mjthrottle(fn, interval, {
leading = true,
trailing = false
} = {}) {
let startTime = 0
let timer = null
const _throttle = function(...args) {
return new Promise((resovle, reject) => {
try {
const nowTime = new Date().getTime()
if (!leading && startTime === 0) startTime = nowTime
const waitTime = interval - (nowTime - startTime)
if (waitTime <= 0) {
if (timer) clearTimeout(timer)
const res = fn.apply(this, args)
resovle(res)
startTime = nowTime
timer = null
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
const res = fn.apply(this, args)
resovle(res)
startTime = new Date().getTime()
timer = null
}, waitTime)
}
} catch (error) {
reject(error)
}
})
}
_throttle.cancel = function() {
if (timer) clearTimeout(timer)
startTime = 0
timer = null
}
return _throttle
}
export default mjthrottle