节流
可类比成技能冷却,在事件触发后n秒内不能再次触发,常用场景是用户频繁点击
代码实现
/**
* 节流
* @param {*} fn 事件处理器
* @param {*} time 冷却时长
* @returns
*/
function throttle (fn, time) {
let timer = null
return function () {
const args = arguments
if (timer) return
fn.apply(this, args)
timer = setTimeout(() => {
timer = null
}, time);
}
}
防抖
可类比成回城,在回城成功之前被打断就需要重新回城,在事件触发n秒后才会执行处理函数,如果n秒内再次触发,就需要重新计时,常用场景有搜索框输入、修改浏览器窗口大小
const debounce = (fn, time) => {
let timer = null
return function () {
const args = arguments
if (timer) {
clearTimeout(timer) // 立即阻止定时器回调函数的执行
}
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, time);
}
}
发布订阅模式
/**
* ? 什么是发布订阅模式
* 订阅者把想订阅的事件注册到调度中心,发布者发布该事件到调度中心,也就是该事件触发时,由调度中心统一调度
* 1. 创建一个类 2. 在这个类里面创建一个调度中心 3. on方法(把函数添加到调度中心)off方法(取消订阅)emit方法(发布者发布事件到调度中心,调度中心处理代码) 4. 确定入参
*/
class EventHub {
constructor() {
// 消息队列
this.message = {}
}
/**
* 订阅
* @param {*} type 事件类型
* @param {*} callback 回调
*/
on (type, callback) {
// 入队,为每个事件类型创建一个数组
this.message[type] = this.message[type] || []
this.message[type].push(callback)
}
/**
* 发布
* @param {*} type 事件类型
* @param {*} data 参数
* @returns
*/
emit (type, data) {
const fnList = this.message[type] // alias
if (!fnList) return
// 对消息队列进行轮询,依次执行
fnList.map(f => f.call(undefined, data))
}
/**
* 取消订阅
* @param {*} type 事件类型
* @param {可选} callback 回调
* @returns
*/
off (type, callback) {
const fnList = this.message[type]
if (!fnList) { return }
// 如果没有传callback就将type对应的缓存都清空
if (!callback) {
fnList = undefined
}
// 如果有callback,就遍历缓存列表,删除callback这个方法 或 被once拦截的方法
let fn
for (let i = 0; i < fnList.length; i++) {
fn = fnList[i]
if (fn === callback || fn.callback === callback) {
fnList.splice(i, 1)
break
}
}
}
/**
* 监听一次
* @param {*} type
* @param {*} callback
*/
once (type, callback) {
// 重写callback,执行后从消息队列中删除
let onceFn = () => {
callback.call(undefined, arguments)
this.off(type, onceFn)
}
//
onceFn.callback = callback // 在事件未emit的情况下,off时访问传入的callback
this.on(type, onceFn) // 注册事件
}
}
const handlerA = () => { console.log('handlerA'); }
const handlerB = () => { console.log('handlerB'); }
const handlerC = () => { console.log('handlerC'); }
const person = new EventHub()
// 注册
person.on('buy', handlerA)
person.on('buy', handlerB)
// 取消订阅
person.off('buy', handlerA)
// 触发
person.emit('buy')
// 监听一次
person.once('buy', handlerA)
// 取消订阅
person.off('buy', handlerA)
// 触发
person.emit('buy')
console.log(person);