Easy to understand
Image stabilization
Usually, when we buy mobile phones or cameras, they all have anti-shake function. The anti-shake function of the camera is the same logically as the anti-shake function here. When we pick up a camera to record a video, our hands shake constantly, but the video doesn’t shake very much. The reason is that the camera ignores the shaking within n milliseconds, so that the camera lens remains in the state of n milliseconds ago.
The throttle
Object movement is continuous in space and time, but we record video frame by frame because the camera ignores object movement in n milliseconds to save storage space. This process can be understood as throttling.
In fact, it is not necessary to cite something different from the thing itself to illustrate some problems, so let’s take the real scene we met when developing the web page.
The real scene
scenario
You are developing a user registration page, and the platform says that the nickname field must be unique, but don’t wait for the user to click the register button to check, do it as soon as possible.
The first thing we thought about was that every time the input field changed, we checked to see if someone had already registered the nickname. If the user is typing very quickly, this query is too fast and puts too much pressure on the server.
Faced with this problem, we can think of two solutions to solve it.
1. If you
Queries are executed only after two changes in the input box exceed n milliseconds, and are not executed if the change interval is less than N milliseconds.Copy the code
2. The throttle
N Only one query is executed for a change in milliseconds.Copy the code
Is it similar to the camera example?
We have two solutions, but how do we implement them at the code level? Let’s try to do this in a straightforward way.
Simple implementation
1. If you:
<input name="username" type="text" oninput="checkUsername(this)">
<script>
var handler;
function checkUsername(it) {
clearTimeout(handler);
handler = setTimeout(() = > {
// TODO
}, 1000)}</script>
Copy the code
We can analyze carefully if these lines of code are plan 1 above.
If the checkUsername function is executed repeatedly within 1000 ms, the setTimeout is cleared repeatedly and a new 1000 ms timed task is set repeatedly. The scheduled task does not have a chance to execute once until you have executed checkUsername more than 1000 milliseconds apart.
2. The throttle:
<input name="username" type="text" oninput="checkUsername(this)">
<script>
var isRuning = false;
function checkUsername(it) {
if(! isRuning) { isRuning =true;
// TODO
setTimeout(() = > isRuning = false.1000)}}</script>
Copy the code
You can analyze these lines of code.
The first time you execute checkUsername,! If isRuning is true, execute the key code, change isRuning to true, set it to 1000 milliseconds before changing isRuning to false. If you execute checkUsername repeatedly in 1000 milliseconds, the key code will not be executed until the timer is executed and the key code is executed again.
The above code is straightforward implementation of the requirements. However, there are a lot of requirements for anti-shake and throttling. After careful analysis, we found that some codes are boilerplate codes, which have nothing TODO with business logic. Our business logic is in TODO, so can we refine it?
refactoring
Image stabilization
The separation of
const debounce = (fun, interval) = > {
let handle;
return (obj) = > {
clearTimeout(handle);
handle = setTimeout(() = >fun(obj), interval); }}Copy the code
First, you write a function that takes two arguments, one for the function to be executed (TODO) and one for the time interval. The function returns a function that, if called consecutively, performs in accordance with the definition of stabilization. Apply the above logic to the analysis.
application
<input name="username" type="text" oninput="checkUsername(this)">
<script>
const checkUsername = debounce(x= > {
// TODO
}, 1000);
</script>
Copy the code
In this way, we only need to focus on the business code.
The throttle
The separation of
const throttle = (fun, wait) = > {
let isRuning = false;
return (obj) = > {
if(! isRuning) { isRuning =true;
setTimeout(() = > isRuning = false, wait) fun(obj); }}}Copy the code
application
<input name="username" type="text" oninput="checkUsername(this)">
<script>
const checkUsername = throttle(x= > {
// TODO
}, 1000);
</script>
Copy the code
Nothing to say, nothing complicated. If you have any questions, leave a message.
Decorator mode
Maybe your project introduces typescript, and TS supports decorator patterns so well that you want to implement them with decorators. Honestly, it’s more elegant.
Image stabilization
The separation of
Start by implementing a shake-proof method decorator.
export default function debounce (interval: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let handle:number
const fun = descriptor.value as Function
descriptor.value = function (. obj:any) {
clearTimeout(handle)
handle = setTimeout(() = > fun.call(this, obj), interval)
}
}
}
Copy the code
If you don’t understand decorators, you can read my previous article or look it up online. My example, however, has practical applications.
The core code is basically the same as above, here to apply ts decorator syntax, and understand the direction of this inside. You have to understand decorators to understand this.
application
This is demonstrated with the help of the Vue project.
<template>
<input name="username" type="text" @input="checkUsername">
</template>
<script lang='ts'>
import { Vue, Component } from 'vue-property-decorator'
+import debounce from './debounce'
@Component({})
export default class Test extends Vue {
+ @debounce(1000)
checkUsername () {
// TODO
}
}
</script>
Copy the code
The application is not easy to say.
Throttling is also written out, not much to say. If you have any questions, please leave a comment.
The throttle
Pull away
export default function throttle (wait: number) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const fun = descriptor.value as Function let isRuning = false descriptor.value = function (... obj: any) { if (! isRuning) { isRuning = true setTimeout(() => { isRuning = false }, wait) fun.call(this, obj) } } } }Copy the code
application
<template>
<input name="username" type="text" @input="checkUsername">
</template>
<script lang='ts'>
import { Vue, Component } from 'vue-property-decorator'
+import throttle from './throttle'
@Component({})
export default class Test extends Vue {
+ @throttle(1000)
checkUsername () {
// TODO
}
}
</script>
Copy the code
conclusion
There are other ways, such as observer mode, where the idea is to convert the event that is constantly being triggered into a custom event, and then to slow that event down by applying a bit of stabilization or throttling in the custom event, and finally to let the observer handle the slowing event. I’m not going to write it here.
In fact, when we encounter a problem, once we understand the phenomenon and nature of the problem, we can search our own knowledge structure and find the corresponding solution.
Note: I have read it and found some problems with the statements.