草庐IT

前端都应该要掌握的防抖和节流

初见雨夜 2023-03-28 原文

说到防抖和节流相信大家都不陌生,这两个东西大家可能多多少少都有用到过,最少也有听过

古人云,温故而知新。虽然可能已经很熟悉防抖和节流了,但不妨再看一看巩固一下知识

什么?你说你不仅不会手写防抖和节流,也没有听过。那也没事,下文会详细介绍的

防抖和节流有什么用?

简单来说,防抖和节流都是用来减少函数执行的频率,以达到优化项目性能或者实现特定功能的效果

防抖

定义:事件被触发一定时间后再执行回调。如果在这段时间内又被触发了,则重新开始计算时间

常用场景

  • 输入框远程查询事件
  • 在线文档自动保存
  • 浏览器视口大小改变

例子

张三在某平台搜索一本书籍,发现搜索建议并不是瞬间就出现的,而是自己输入词组结束后出现的。那么该平台在此搜索框可能做了什么操作?

代码实现

<body>
  <input type="text" id="searchElement" />
</body>
<script>
  const searchElement = document.getElementById('searchElement');
  const debounce = (fn, initial) => {
    let timer = null;
    return () => {
      clearTimeout(timer);
      timer = setTimeout(fn, initial);
    };
  };

  searchElement.oninput = debounce(function (event) {
    const value = searchElement.value;
    if (value) console.log(value, '请求值');
  }, 1000);
</script>

节流

定义:在单位时间内只触发一次函数,若单位时间内多次触发只有一次生效

常用场景

  • 按钮提交事件(当然也可做成点击后就loading)
  • 页面滚动事件的触发
  • 累计计算鼠标移动距离

例子

张三参加某平台周年庆活动,他选购了某热门饮品并一直点击抢购按钮,却发现并不是每次点击都会有响应的。那么该平台前端可能做了什么限制?

代码实现

<body>
  <button type="submit" id="buttonElement">抢购</button>
</body>
<script>
  function throttle(fn, interval) {
    let timer;
    return (event) => {
      if (timer) return false;
      timer = setTimeout(() => {
        clearTimeout(timer);
        timer = null;
        fn(event);
      }, interval);
    };
  }

  var btnClick = document.getElementById('buttonElement');
  btnClick.addEventListener('click', throttle(function (event) {
    console.log(event, '点击了')
  }, 1000));
</script>

可以看到,张三疯狂点击抢购,但还是每秒只响应1次

节流(立即执行)

细心的同学可能发现了,上面这个代码有个弊端,那就是在张三第一次点击的时候也隔了1秒才响应,这不免也太坑了。正常来说第一次应该直接响应的,并且在连续点击结束后的第一次也应该立即触发,其实想实现这样的效果也不难

<body>
  <button type="submit" id="buttonElement">抢购</button>
</body>
<script>
  function throttle2(fn, interval) {
      let init = false; // 引入一个参数记录状态
      let timer;
      return (event) => {
          if (init) return;
          init = true;
          clearTimeout(timer);
          timer = setTimeout(() => {
              init = false;
          }, interval);
          fn(event);
      }
  }

  var btnClick = document.getElementById('buttonElement');
  btnClick.addEventListener('click', throttle2(function (event) {
      console.log(event, '点击了')
  }, 2000));
</script>

可以看到第一次点击直接打印,第二次疯狂点击只打印一次,最后一次点击也是直接打印

引入Lodash实现

GitHub地址:https://github.com/lodash/lodash
官方文档:https://www.lodashjs.com/

防抖

import _ from 'lodash';
debounceHandle: _.debounce(function() {
  console.log('业务代码');
}, 2000, {       // 在n毫秒内触发
  leading: true, // 第一次点击立刻执行,默认为true
  trailing: true // 节流结束后立刻执行,默认为true
});

节流

import _ from 'lodash';
throttleHandle: _.throttle(function() {
  console.log("业务代码");
}, 2000);

有关前端都应该要掌握的防抖和节流的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  3. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  4. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  5. ruby-on-rails - 我现在(2010 年 1 月)应该使用哪个版本的 Ruby? - 2

    我有1.8.6附带的VanillaMacOSXLeopard。我是RoR的新手,所以会学习网上的教程。在使用更高版本的Ruby时,我是否可能会发现遵循它们的问题?我目前正在查看提到1.8.6和1.8.7的这个-http://www.railstutorial.org/book 最佳答案 RoR教程对两者都适用,但如果您正在学习Ruby,则应该学习1.9。Rails3将不支持1.8.6,所以我会选择1.8.7或1.9。我还推荐使用RVM在Ruby版本之间切换。 关于ruby-on-rail

  6. ruby-on-rails - Rails 中的类实例变量应该在互斥体中设置吗? - 2

    假设我的Rails项目中有一个设置实例变量的Ruby类。classSomethingdefself.objects@objects||=begin#somelogicthatbuildsanarray,whichisultimatelystoredin@objectsendendend是否可以多次设置@objects?是否有可能在一个请求期间,在上面的begin/end之间执行代码时,可以在第二个请求期间调用此方法?我想这实际上归结为Rails服务器实例如何fork的问题。我应该改用Mutex还是线程同步?例如:classSomethingdefself.objectsreturn@o

  7. ruby - 构建网络蜘蛛时,应该使用递归吗? - 2

    构建一个深度优先的网络蜘蛛,这意味着它将访问第一页上的所有链接,然后转到每个链接,并访问所有第二页上的链接...你应该使用递归吗?我发现这是CPU密集型的。defrecursion()linkz_on_first_page.eachdo|link|recursion(link)endendrecursion(firstpage) 最佳答案 绝对不是,由于万维网的实际性质,您很快就会遇到问题。当您访问带有主导航部分的网站时,每个页面都链接到其他页面,您就进入了一个无限循环。您可以跟踪您处理了哪些链接,但即便如此,递归循环并不真正适合万

  8. ruby-on-rails - 为什么 Rails 菜鸟不应该使用 Gem Devise? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我是ruby​​onrails菜鸟。相比之下,我的HTMLCSSjavascript和jQuery相当不错。最近我使用MichaelHartl的教程进入了RubyonRails:http://ruby.railstutorial.org/ruby-on-rails-tutorial-book.但是,唉,我正在尝试构建自己的项目并使用gemdevise作为进

  9. ruby - 下拉菜单在应该被选中的时候没有被选中……为什么? - 2

    我正在尝试解决我们测试中的一个错误,我认为它应该有效。我很确定这是selectize或capybara中的错误,但我不明白为什么。我已经进入了capybara的源代码,一切似乎都在正常工作。我真的不确定如何前进。为了测试这个错误,我已经尽可能地把这个错误剥离成一个小的testapplication.请参阅下面的设置bugs/show.html.erbOneTwoThreeFourOneTwoThreeFourbug_spec.rbfeature'bug'doit"specsetup",js:truedovisitbug_pathfind('div.selectize-inputinpu

  10. ruby-on-rails - 我应该使用哪个适用于 Ruby 的 CouchDB 适配器? - 2

    一些我找到的选项是ActiveCouchCouchRESTCouchPotatoRelaxDBcouch_foo我更喜欢GitHub上的项目,因为这让我更容易fork和推送修复。所有这些都符合该要求。我习惯了Rails,所以我喜欢像ActiveRecord模型一样工作的东西。另一方面,我也不希望我和Couch之间太多--毕竟我使用它作为我的数据库是有原因的。最后,它们似乎都得到了相当积极的维护(couch_foo可能是个异常(exception))。所以我想这归结为(不可否认和不幸的)主观:有没有人对他们有过好的或坏的经历? 最佳答案

随机推荐