/*
callback:callback functionname
interval: millisecond */ function debounce(callback, interval) {
let debounceTimeoutId; return function(...args) {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => callback.apply(this, args), interval);
};
} function throttle(callback, interval) {
let enableCall = true; return function(...args) {
if (!enableCall) return; enableCall = false;
callback.apply(this, args);
setTimeout(() => enableCall = true, interval);
}
}
/*
* 频率控制 返回函数连续调用时,fn 执行频率限定为每多少时间执行一次
* @param fn {function} 需要调用的函数
* @param delay {number} 延迟时间,单位毫秒
* @param immediate {bool} 给 immediate参数传递false 绑定的函数先执行,而不是delay后后执行。
* @param debounce {bool} 给 immediate参数传递false 绑定的函数先执行,而不是delay后后执行。debounce
* @return {function}实际调用函数
*/ var throttle = function(fn, delay, immediate, debounce) {
var curr = +new Date(),//当前时间
last_call = 0,
last_exec = 0,
timer = null,
diff, //时间差
context,//上下文
args,
exec = function () {
last_exec = curr;
fn.apply(context, args);
};
return function () {
curr = +new Date();
context = this,
args = arguments,
diff = curr - (debounce ? last_call : last_exec) - delay;
clearTimeout(timer);
if (debounce) {
if (immediate) {
timer = setTimeout(exec, delay);
} else if (diff >= 0) {
exec();
}
} else {
if (diff >= 0) {
exec();
} else if (immediate) {
timer = setTimeout(exec, -diff);
}
}
last_call = curr;
}
};
var setval =  function(){
var mydate = new Date();
var s = mydate.getSeconds();
var ms = mydate.getMilliseconds();
document.getElementById("ipt").value=s+":"+ms; } //以下两种绑定方法都可以,特别是jquery绑定时.注意 $("#btn")[0]
//document.getElementById("btn").onclick = throttle(function(){ setval(); },1000,true,false); 
$("#btn")[0].onclick = throttle(function(){ setval(); },1000,true,false);

以下转自:https://programmingwithmosh.com/javascript/javascript-throttle-and-debounce-patterns/

 June 17th, 2019

Comments

JavaScript patterns: Throttle and Debounce

Do you need to handle a specific event, but you want to control how many times your handler will be called in a given period of time? This is a very common problem and often happens when listening to events such as scrollmousemove or resize, which are triggered dozens of times a second. But sometimes it’s desirable even for less “frenetic” events, like, for example, to limit an action that occurs when a certain button is clicked. In this article, we’ll cover two patterns to control the repeated call of event handlers: throttle and debounce.

The example app

In order to understand both patterns, we will use a simple example application that shows the current mouse coordinates in the screen and how many times these coordinates were updated. By looking at this counter, you will find it easier to compare how these two techniques can control the calling of an event handler. This is our app without any event control technique applied:

render();

document.body.addEventListener('mousemove', logMousePosition);

let callsCount = 0;
const positionsEl = document.querySelector('.app__positions');
function logMousePosition(e) {
callsCount++;
positionsEl.innerHTML = `
X: ${e.clientX},
Y: ${e.clientY},
calls: ${callsCount}
`;
} function render() {
document.querySelector('#app').innerHTML = `
<h1 class="app__title">Mouse position (Without event control) </h1>
<div class="app__positions"></div>
`;
}

And here is how this initial version of our app behaves:

Full example.

Did you notice the calls count? In just 7 seconds, the logMousePosition function was called 320 times! Sometimes you don’t want a given event handler to be called so many times in a period of time so short. Now, let’s see how to solve this issue.

Throttle

The throttle pattern limits the maximum number of times a given event handler can be called over time. It lets the handler be called periodically, at specified intervals, ignoring every call that occurs before this wait period is over. This technique is commonly used to control scrolling, resizing and mouse-related events.

We need to adapt the example app to use the throttle pattern. In order to do so, let’s change the addEventListener call of the original code to include the throttling logic:

let enableCall = true;
document.body.addEventListener('mousemove', e => {
if (!enableCall) return; enableCall = false;
logMousePosition(e);
setTimeout(() => enableCall = true, 300);
});

In the above code:

  1. We’re declaring a enableCall variable to control if the throttling interval is already over. This flag is initially set to true, in order to allow the handler to be called the first time.
  2. Every time a mousemove event is triggered, we test if the enableCall variable is true. If not, that means that the minimum wait period is not over yet and we won’t call the event handler that time.
  3. However, if the enableCall variable is true, we can execute the event handler normally. However, before doing so, we need to set our control flag to false in order to prevent the handler to be called again during the wait interval.
  4. After calling the event handler, we use the setTimeout function to set our flag back to true after 300 milliseconds. This way, our handler will only be authorized to run again when this minimum interval is over.

Full example.

Now, let’s see how the app behaves after applying this technique:

The throttling logic works perfectly! Now, there’s a minimum interval of 300 milliseconds between the updates, drastically reducing our calls count.

A reusable throttle function

In order to make this code reusable, let’s extract it to a separate function:

document.body.addEventListener('mousemove', throttle(logMousePosition, 300));

function throttle(callback, interval) {
let enableCall = true; return function(...args) {
if (!enableCall) return; enableCall = false;
callback.apply(this, args);
setTimeout(() => enableCall = true, interval);
}
}

The logic here is the same as above. When called, the throttle function returns a new event listener. In this version, we’re using a common function in order to preserve the original this context and apply it to the passed callback.

Full example.

Debounce

The debounce pattern allows you to control events being triggered successively and, if the interval between two sequential occurrences is less than a certain amount of time (e.g. one second), it completely ignores the first one. This process is repeated until it finds a pause greater than or equal to the desired minimum interval. Once it happens, only the last occurrence of the event before the pause will be considered, ignoring all the previous ones. A common use case for this pattern is to limit requests in a search box component that suggests topics while the user is typing.

Let’s adapt our example app to use the debounce pattern:

let debounceTimeoutId;
document.body.addEventListener('mousemove', (e) => {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => logMousePosition(e), 300);
});

The above piece of code contains the essence of the debounce pattern. Every time the event we want to control is fired, we schedule a call to the handler for 300 milliseconds later (by using setTimeout) and cancel the previous scheduling (with clearTimeout). This way, we’re constantly delaying the execution of the handler function until the interval between two sequential events is equal to or greater than a given threshold time.

To sum up:
Let’s say we have a given event being triggered two times (A and B) and there’s an X interval between these two occurrences. If we want to control this event by applying a debounce of Y milliseconds, here’s how it will work:

  • If X < Y, the A call will be ignored.
  • If X >= Y, the B call is considered.
  • In both cases, if the new interval after B is greater than or equal to Y, B will be considered too.

Now, let’s see how it behaves in practice:

Full example

A reusable debounce function

Finally, we can extract the pattern logic to a reusable function. This way, we can easily apply it in similar situations in the future:

document.body.addEventListener('mousemove', debounce(logMousePosition, 300));
function debounce(callback, interval) {
let debounceTimeoutId; return function(...args) {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => callback.apply(this, args), interval);
};
}

Full example

Conclusion

  • The debounce pattern delays the calling of the event handler until a pause happens. This technique is commonly used in search boxes with a suggest drop-down list. By applying this pattern, we can prevent unnecessary requests to the backend while the user is typing.
  • The throttle pattern is more suitable for events that are triggered many times in a short period of time. This technique is normally used to control scrolling, resizing and mouse-related events. By using throttle, we can filter repeated executions of an event handler, enforcing a minimum wait time between calls.

If you really want to master the fundamentals of JavaScript, you need to check out Mosh’s JavaScript course. It’s the best JavaScript course out there! And if you liked this article, share it with others as well!

js 节流函数 throttle的更多相关文章

  1. 关于js节流函数throttle和防抖动debounce

    废话不多说,直奔主题. 什么是throttle和debounce? 这两个方法的主要目的多是用于性能优化.最常见的应用尝尽就是在通过监听resize.scroll.mouseover等事件时候的性能消 ...

  2. js节流函数和js防止重复提交的N种方法

    应用情景 经典使用情景:js的一些事件,比如:onresize.scroll.mousemove.mousehover等: 还比如:手抖.手误.服务器没有响应之前的重复点击: 这些都是没有意义的,重复 ...

  3. js节流函数高级版

    节流函数其主要作用就是防止用户在短时间内多次触发该事件. <!DOCTYPE html> <html lang="en"> <head> < ...

  4. 简单的节流函数throttle

    在实际项目中,总会遇到一些函数频繁调用的情况,比如window.resize,mouseover,上传进度类似的触发频率比较高的函数,造成很大的性能损耗,这里可以使用节流函数来进行性能优化,主要是限制 ...

  5. JavaScript 节流函数 Throttle 详解

    在浏览器 DOM 事件里面,有一些事件会随着用户的操作不间断触发.比如:重新调整浏览器窗口大小(resize),浏览器页面滚动(scroll),鼠标移动(mousemove).也就是说用户在触发这些浏 ...

  6. Javascript中 节流函数 throttle 与 防抖函数 debounce

    问题的引出 在一些场景往往由于事件频繁被触发,因而频繁地进行DOM操作.资源加载,导致UI停顿甚至浏览器崩溃. 在这样的情况下,我们实际上的需求大多为停止改变大小n毫秒后执行后续处理:而其他事件大多的 ...

  7. js实现防抖函数和节流函数

    防抖函数(debounce) 含义:防抖函数指的是在特定的时间内没有再次触发,才得以进行接下来的函数运行: 用途:当window.onresize不断的调整大小的时候,为了避免不断的重排与重绘,可以用 ...

  8. vue实现输入框的模糊查询(节流函数的应用场景)

    上一篇讲到了javascript的节流函数和防抖函数,那么我们在实际场合中该如何运用呢? 首先,我们来理解一下:节流函数首先是节流,就是节约流量.内存的损耗,旨在提升性能,在高频率频发的事件中才会用到 ...

  9. [概念] js的函数节流和throttle和debounce详解

    js的函数节流和throttle和debounce详解:同样是实现了一个功能,可能有的效率高,有的效率低,这种现象在高耗能的执行过程中区分就比较明显.本章节一个比较常用的提高性能的方式,通常叫做&qu ...

随机推荐

  1. Web前端开发笔试&面试_05_other 2016104399MS

    1.数据传送的方式,get post 的区别是? 2.你要怎么绑定页码(比如给你第三页,)? 3.数据流是如何实现,用for 循环? 4.轮播怎么实现?用原生JS实现. 5.布局,B是固定宽度,A的内 ...

  2. 转:Scrapy安装、爬虫入门教程、爬虫实例(豆瓣电影爬虫)

    Scrapy在window上的安装教程见下面的链接:Scrapy安装教程 上述安装教程已实践,可行.(本来打算在ubuntu上安装Scrapy的,但是Ubuntu 磁盘空间太少了,还没扩展磁盘空间,所 ...

  3. 【性能诊断】十、性能问题综合分析(案例1,windbg、Network Monitor)

    [问题描述]:       产品中某业务功能A,在进行"刷新"->选择制单->新增->切换其他行等一系列操作后,突然发生客户端不响应的现象.       经反复测 ...

  4. mysql四种事务隔离级的说明

    ·未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据 ·提交读(Read Committed):只能读取到已经提交的数据.Oracle等多数数据库默 ...

  5. input绑定datapicker控件后input再绑定blur或者mouseout等问题

    input绑定datapicker控件后input再绑定blur或者mouseout等问题 问题描述:今天在修改一个东西的时候需要给一个input输入域绑定blur事件,从而当它失去焦点后动态修改其中 ...

  6. 解决SQLite3数据库Error: database disk image is malformed

    这种错误的提示一般都是数据库文件出现了问题,具体导致问题的原因不必深究,我们只讨论这种问题的饿解决方法: 比如数据库:test.db 这里还要分两种情况: 情况一: sqlite3 test.db & ...

  7. 剑指offer系列21--二叉搜索树的后续遍历序列

    * 21[题目]输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果. * 如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. * [注]二叉搜索树特点:左子树比根结 ...

  8. IDrac的console无法键盘输入

    IDrac的console无法键盘输入问题? 解:disable IE 的protect 功能 (Idrac的正常工作需要先安装Java,同时IDrac只支持IE和Firefox.) 方法: IE-& ...

  9. c++的历史-异常

    1.异常出现的目的 在c++语言的设计和演化中,Bjarne Stroustrup说过异常的设计假定如下情况: 基本上是为了处理错误 与函数定义相比,异常处理是很少的 与函数调用相比,异常出现的频率较 ...

  10. 128. Longest Consecutive Sequence

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...