Throttling means that events are triggered frequently, but only respond once in a time period.
The actual application scenario is: I think it is similar to anti shake, which is a scenario of high-frequency events.
Throttling process: set a small cycle. If an event is triggered in this small cycle, no matter how many times it is triggered, it is good to respond once at the end of the cycle.
Comparison with anti shake: anti shake is the last response to this wave of high-frequency events; Throttling means that if the high-frequency event lasts for a long time, it will respond once or several times during the duration.
The timeline picture of this article can help understand: js anti shake and throttling
1, setInterval implementation
At first I was more indifferent. Since you want to set the interval according to a fixed period, you have to set setinterval globally:
<script> document.addEventListener('DOMContentLoaded', function () { var timer = null; var flag = false; document.addEventListener('scroll', function () { flag = true; }); timer = setInterval(function () { if (flag == true) { flag = false; console.log('you have scrolled during last period'); } else { //console.log('no scrolling during last period'); } }, 1000); }); </script>
After setInterval is set globally, flag detection is performed every 1000ms:
If the flag is true, it indicates that there is one or more scrolling in the previous 1000ms cycle, and the action can be executed (output "you have scrolled during last period").
If the flag is false, there is no need to perform an action. Here, an else branch is placed for demonstration and "no monitoring during last period" is output.
(if your browser does not support listening to the scoll of document, try to change it to window or document.body; if the effect of 1000ms cycle is not strong, try to change it to 500 or 100.)
The flag here is generally called throttle valve. When I write here, I think of the throttle valve that has done the rotation map before, but I still can't immediately transfer the idea and code implementation to this common throttling scenario.
2, setTimeout is implemented and encapsulated
Why did you just give up? Because after reading the diagram in the above article, I think there must be continuous cycles. In fact, it is not necessary. There can be intervals between cycles, not necessarily continuous.
That is, you can use setTimeout instead of setInterval. The following process is envisaged:
(1) Respond to the first trigger of the first wave of high-frequency events (set timeout and start cycle).
(2) When the timeout is reached, the cycle is at the end and the action is executed.
(3-1) after that, if the first wave of high-frequency event is still triggered continuously, it will respond immediately (set the second timeout and start the second cycle); In this case, there is no interval between the two cycles, which is a continuous cycle.
(3-2) if the first wave of high frequency event stops before the end of the first cycle, the second timeout will not be set immediately; The second timeout will not be set until the first trigger of the second wave of high-frequency event to start the second cycle; In this case, there will be an interval between the two cycles.
Use setTimeout instead and encapsulate it:
<script> document.addEventListener('DOMContentLoaded', function () { function throttle(handler, period) { var flag = true; var timer = null; return function () { if (flag == true) { flag = false; timer = setTimeout(function () { handler(); flag = true; }, period); } else { //console.log('nothing happened during last period'); } }; } document.addEventListener('scroll', throttle(function(){ console.log('you have scrolled during last period'); }, 1000)); }); </script>
Done. You can compare the code implementation of anti chattering and throttling, which are somewhat similar. The difference is:
(1) For anti shake, the timeout should be cleared and then set. There will be no repeated timeout.
(2) Throttling is to use the throttle valve variable to block the repeated timeout, which will be automatically completed and cleared when the timeout arrives.
3, More: unwrapping encapsulated functions and closure problems
For me, returning a function is still relatively novel, and there is not much contact. In addition, a flag is declared in the throttle() function. Will the throttle() function be called and a new flag variable be declared after each scroll? If there are many flags at the same time, it will be a mess, and it is impossible to correctly judge whether the response action should be performed.
So I tried to disassemble the encapsulated functions and found that the declarations of flag and timer must be placed outside addEventListener() and become global variables. Disassemble as follows:
<script> document.addEventListener('DOMContentLoaded', function () { var flag = true; var timer = null; document.addEventListener('scroll', function () { if (flag == true) { flag = false; timer = setTimeout(function () { console.log('you have scrolled during last period'); flag = true; }, 1000); } else { //console.log('nothing happened during last period'); } }); }); </script>
Explain what problem:
(1) The throttle() function handles the original handler of scroll, which is equivalent to modifying the original handler and providing an "enhanced version" of handler at one time; There is no repeated call in the form of this return function. Only throttle() is called once, and the "enhanced" handler is repeatedly called by subsequent scroll.
(2) After disassembly, the flag and timer must be written outside addEventListener(), because the writing inside is written in the handler. The handler will be called repeatedly, and the flag and timer will be declared repeatedly.
(3) The encapsulated throttle() returns a function that wraps the original handler. Here, you must write flag and timer outside return, but you don't have to write them outside throttle() as global variables; The reason why you can't write to return is (2). You can write to throttle() because the function of return refers to flag and timer to form a closure; throttle() is not called many times, so it does not declare new flag and timer. In addition, the closure variables will not be recycled, so it is OK.