angular 防抖和节流踩坑

如果在angualr项目中实现防抖节流,可以使用封装好的模块,比如rxjs。

但今天说的是使用原始的防抖节流方法遇到的问题:

节流为例,先贴一段常见的原始节流代码

function throttle(fn) {
      let canRun = true; // 通过闭包保存一个标记
      return function () {
        if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
        canRun = false; // 立即设置为false
        setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
          fn.apply(this, arguments);
          // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
          canRun = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));

通常都是以闭包的形式实现节流代码,然后再看触发方式window.addEventListener,网上大多数介绍防抖和节流的例子,都是用window.addEventListener来监听,等待触发的。

然而!应用到angular项目中时,代码是这样的:

模板:<input type="text" (change)="search()" />

search(){

// 节流处理,间隔时间处理一次

this.throttle(func, 1000);

}

坑一:我们期望input输入时,进行节流处理,然而事与愿违,发现throttle()并没有触发,也许聪明的你已经发现,原始代码使用节流方法,是通过回调函数,而我们现在是直接调用,this.throttle(func, wait)的结果只是一个匿名函数,并没有执行!所以应该这样调用:

模板:<input type="text" (change)="search()" />

search(){

// this.throttle(func, wait)返回匿名函数,要进行调用

this.throttle(func, 1000)();

}

坑二:现在函数可以执行了,我们期望无论input怎么触发,每1000ms执行一次,但很快我们发现并没有节流成功!传入的func函数,还是每次触发都会执行!这是为什么?其实中了闭包的坑!先看个闭包的例子:

function outerFn(){
  var i = 0; 
  function innerFn(){
      i++;
      console.log(i);
  }
  return innerFn;
}
var inner = outerFn();  //每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同,都会重新创建一个新的地址
inner();
inner();
inner();
var inner2 = outerFn();
inner2();
inner2();
inner2();   //1 2 3 1 2 3

闭包相关例子可以看着篇:https://blog.csdn.net/weixin_43586120/article/details/89456183

上面的例子可以看出,每次执行outerFn()时,都会开辟一块空间,这就导致变量i的值不能保持连续!结合本例,看一下上面的节流为什么不生效?就是每次input触发,都会执行this.throttle(func, 1000)();而this.throttle(func, 1000)每次执行都新开辟一块空间,这样就导致内部变量canRun 这个标志位每次都会初始化,根本起不到标志位的作用!那么怎么解决呢?重点是this.throttle(func, 1000)只执行一次,把它返回的匿名函数拿到,以后触发执行这个匿名函数就行了!

    constructor() {
//构造函数只执行一次,但弊端还是会引入了一个全局变量,不过这不是本文讨论的重点
    this.fun = this.throttle(this.func, 1000);
}
search(){

// 每次执行返回匿名函数

this.fun();

}

这样每次执行this.fun()时,每次取标志位变量,就是从同一个地址去获取,当然就生效了!其实这个问题是闭包引起的,如果不使用闭包,不考虑全局变量污染,那么实现节流就不会遇到这个问题。

最后,回到最初的原始代码示例,window.addEventListener('resize', throttle(sayHi))这样监听回调为什么没有这个问题?因为throttle(sayHi)只执行了一次,就是在执行window.addEventListener('resize', throttle(sayHi))语句时执行了一次,把返回的函数作为回调函数,每次resize触发,就会执行已经返回的回调函数!

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Angular 中,防抖(debounce)是一种用于控制函数执行频率的技术。它可以限制函数在连续触发时的执行次数,减少不必要的计算和网络请求。 要在 Angular 中实现防抖,你可以使用 RxJS 库提供的 `debounceTime` 操作符。RxJSAngular 中常用的响应式编程库。 首先,确保你已经在项目中引入了 RxJS。你可以通过以下方式导入 `debounceTime`: ```typescript import { debounceTime } from 'rxjs/operators'; ``` 然后,在需要应用防抖的地方,将 `debounceTime` 操作符应用于触发函数的 Observable。 假设你有一个触发搜索的输入框,并且你希望等待用户停止输入一段时间后再触发搜索函数。你可以使用以下代码实现防抖: ```typescript import { Component } from '@angular/core'; import { Subject } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; @Component({ selector: 'app-search', template: ` <input (input)="handleSearch($event.target.value)" /> ` }) export class SearchComponent { searchSubject = new Subject<string>(); constructor() { this.searchSubject.pipe( debounceTime(300) // 设置防抖时间为300ms ).subscribe((value) => { // 在这里执行搜索逻辑 console.log('Searching for:', value); }); } handleSearch(value: string) { this.searchSubject.next(value); } } ``` 在上述代码中,`searchSubject` 是一个 Subject,它负责接收输入框的值。通过使用 `debounceTime` 操作符,并设置防抖时间为300毫秒,确保搜索函数在用户停止输入300毫秒后才会执行。 当用户输入时,`handleSearch` 方法会将输入值发送给 `searchSubject`。然后,`searchSubject` 会触发防抖逻辑,等待300毫秒后,调用 `subscribe` 中的回调函数进行搜索操作。 这样,就实现了在 Angular 中使用防抖的功能。希望对你有所帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值