业务保存,删除,修改幂等性防护问题

业务保存,删除,修改幂等性防护问题

幂等性:无论你操作多少次业务,最终的结果和预期是一致。

针对的业务:增加(重点处理逻辑),修改,删除

select 不会有幂等性问题:你不论执行多少次查询都一样的结果。

服务端防护

  • 数据库
  • 锁 redis

前端的防护

用户在在下单,注册,抢购等场景,可能因为网络的问题,或者延迟,或者用户习惯的问题,会疯狂的点击按钮。其实程序一定要做:截流和防抖。

作用:在某一时间范围内300ms,不论用户点击多少次,以最后一次为准。(比如:300ms 疯狂点击10次,9次无效,1次有效。)

概述

防抖函数 debounce 指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次。假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 秒,直至新的 3 秒内没有函数调用请求,此时执行函数,不然就以此类推重新计时。

举一个小例子:假定在做公交车时,司机需等待最后一个人进入后再关门,每次新进一个人,司机就会把计时器清零并重新开始计时,重新等待 1 分钟再关门,如果后续 1 分钟内都没有乘客上车,司机会认为乘客都上来了,将关门发车。

此时「上车的乘客」就是我们频繁操作事件而不断涌入的回调任务;「1 分钟」就是计时器,它是司机决定「关门」的依据,如果有新的「乘客」上车,将清零并重新计时;「关门」就是最后需要执行的函数。

如果你还无法理解,看下面这张图就清晰多了,另外点击 这个页面 查看节流和防抖的可视化比较。其中 Regular 是不做任何处理的情况,throttle 是函数节流之后的结果(上一小节已介绍),debounce 是函数防抖之后的结果。

定时器

if(this.stimer)clearTimeout(this.stimer);
this.stimer = setTimeout(() => {
	fn();//处理逻辑
},3000);

开关机制

  if(!this.submitFlag){
      alert("请稍后,正在保存中....")
      return;
  }
  this.submitFlag = false;//关住

防抖

function debounce(fn,wait){
    if(this.女孩子)clearTimeout(this.stimer);
    this.女孩子 = setTimeout(() => {
        fn();//处理逻辑
    },wait);
}

这种会存在什么问题?

问题一个:this.stimer 是公共的。

  • debounce(注册,2000) – 小文
  • debounce(登录,2000)–小胖
  • debounce(下单,2000)–小张
// 实现 1
// fn 是需要防抖处理的函数
// wait 是时间间隔
function debounce(fn, wait = 50) {
    // 通过闭包缓存一个定时器 id
    let timer = null
    // 将 debounce 处理结果当作函数返回
    // 触发事件回调时执行这个返回函数
    return function(...args) {
          // 如果已经设定过定时器就清空上一次的定时器
        if (timer) clearTimeout(timer)

          // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, wait)
    }
}

使用

// DEMO
// 执行 debounce 函数返回新函数
const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
// 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了')
document.addEventListener('scroll', betterFn)

截流

// fn 是需要节流处理的函数
// wait 是时间间隔
function throttle(fn, wait) {

  // previous 是上一次执行 fn 的时间
  // timer 是定时器
  let previous = 0, timer = null

  // 将 throttle 处理结果当作函数返回
  return function (...args) {

    // 获取当前时间,转换成时间戳,单位毫秒
    let now = +new Date()

    // ------ 新增部分 start ------ 
    // 判断上次触发的时间和本次触发的时间差是否小于时间间隔
    if (now - previous < wait) {
         // 如果小于,则为本次触发操作设立一个新的定时器
       // 定时器时间结束后执行函数 fn 
       if (timer) clearTimeout(timer)
       timer = setTimeout(() => {
          previous = now
            fn.apply(this, args)
        }, wait)
    // ------ 新增部分 end ------ 

    } else {
       // 第一次执行
       // 或者时间间隔超出了设定的时间间隔,执行函数 fn
       previous = now
       fn.apply(this, args)
    }
  }
}

// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 节流执行了'), 1000)
// 第一次触发 scroll 执行一次 fn,每隔 1 秒后执行一次函数 fn,停止滑动 1 秒后再执行函数 fn
document.addEventListener('scroll', betterFn)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值