Background:
- Thinking about the event loop mechanism triggered by event stabilization, partially asynchronously placed in the execution order outside the closure
- Code combat: React event handler onClick = call function “this.fn()” directly, Bind this “this.fn.bind(this)” when called, or bind this “() => this.handleclick () when called with the arrow function
Say first conclusion
In buffeting, part of the asynchronous closure is placed outside the closure, resulting in the following result:
.// Some asynchronous parts are not shaken
_this.props.dispatch({
type: "test/debounce",
param
})
.then(() = > {
_this.editData()
})
// Part of the asynchronous end is not buffered
.then(() = > {
return function () {
console.log('-- first timeout: ', timeout) 2 / / 2
clearTimeout(timeout); // Every time the input value is triggered, the previous setTimeout is cleared
console.log('-- timeout: ', timeout); / / 3. 3
timeout = setTimeout(() = > { / / 4 4
_this.updateAge() // Retrieve page data again
console.log('-- I'm setTimeout, anti-shake cleanup functions'."-- timeout value:", timeout)
}, 1000) // Note that if you write code that refers to this, you need to declare who this is, because there is no reference to this in the arrow function
console.log('-- Closure in debounce completes execution ', timeout)
}()
})
...
Copy the code
- The synchronization code is executed first (i.e. after two clicks), and setTimeout is executed last.
- This. UpdateAge is not cleared because setTimeout is not defined when clearTimeout is executed
- The final number of times setTimeout is executed is the number of clicks
Author: Lin Xuan Link: juejin.cn/post/698919… The copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.
Way to write — The correct way to write
Step 1: Define the click method in Render
- Option 1 in the code below: not feasible;
Because bind is a function that returns a change to this, it will change debounce this and return it as it is;
And what we’re going to do is debounce() and to do that, we’re going to have onClick = debounce(), which returns a closure, and ultimately what we’re going to do is we’re going to execute the function that returns debounce
- Option 2 in the code below: Yes;
Debounce (), which returns the closure defined inside;
Render will execute debounce(), but it doesn’t really matter, we’re mainly executing the function returned from debounce(), and debounce doesn’t have too much logic in front of its definition to go wrong
// render
/ / way
{/* - */}
2 / / way
<span className={styles.left} onClick={this.debounce('subtract')}>-</span>
Copy the code
Step 2: Define the Debounce event
- Method 1: Write all functions inside setTimeout, ok
To use closures properly, a cleanup function is one that clears all functions, not the outside – the Debounce definition in example 2
debounce = (option) = > {
console.log('-- Enter the debounce method ')
let param={};
// Handle some logic
if (option === 'str') {
param = {a:1}}else {
param = {a:1}}const _this = this;
let timeout = null;
return function () {
console.log('-- first timeout: ', timeout)
clearTimeout(timeout);
console.log('-- timeout: ', timeout)
timeout = setTimeout(() = > { / / 4 4Arunachal Pradesh// The buffering function **
_this.props.dispatch({
type: "test/debounce",
param
})
.then(() = > {
_this.editData()
})
.then(() = > {
_this.updateAge()
})
**// End **
console.log('-- I'm setTimeout, anti-shake cleanup functions'."-- timeout value:", timeout)
}, 500)
console.log('-- Closure in debounce completes execution ', timeout)
}
}
Copy the code
- Below is the execution sequence when the button is clicked twice quickly:
SetTimeout clears all functions and only executes the last request, so only prints ‘~~~ I am requesting ‘once.
The variable value of setTimeout is a number that uniquely identifies setTimeout
2 – Incorrect writing (write part of the closure asynchronously, just want to clear some function jitter)
First step: Render definition
-
Because of the error of writing the second method, which is to write part of the asynchronous closure outside, just want to clear part of the function jitter,
-
Render, the asynchrons in debounce() will be executed, and perhaps some data will be updated. Render may result in an error
-
Bind (), which changes this, returns a function body instead of executing the function; Instead of causing debounce to execute on render, debounce will be executed on onClick
-
Can only write the following, two kinds of writing, the two see writing difference: react.docschina.org/docs/handli…
<span className={styles.left} onClick={this.debounce.bind(this.'subtract')}>-</span>
Copy the code
Step 2: Define debounce
-
Write part of the asynchronous closure outside, do not tremble; I just want to clear some function jitter,
-
See the following figure for the execution results, and see “conclusion” below for reasons.
// Add or subtract ages
debounce = (option) = > {
console.log('-- Enter the debounce method ')
let param={};
// Handle some logic
if (option === 'str') {
param = {a:1}}else {
param = {a:1}}const _this = this;
let timeout = null;
// Some asynchronous parts are not shaken
_this.props.dispatch({
type: "test/debounce",
param
})
.then(() = > {
_this.editData()
})
// Part of the asynchronous end is not buffered
.then(() = > {
return function () {
console.log('-- first timeout: ', timeout) 2 / / 2
clearTimeout(timeout);
console.log('-- timeout: ', timeout); / / 3. 3
timeout = setTimeout(() = > { / / 4 4
_this.updateAge()
console.log('-- I'm setTimeout, anti-shake cleanup functions'."-- timeout value:", timeout)
}, 1000)
console.log('-- Closure in debounce completes execution ', timeout)
}()
})
}
Copy the code
The reason why the execution result is incorrectly written
Reference source: segmentfault.com/a/119000002…
-
Because the event loop mechanism is the primary task – > micro task – > macro task, setTimeout is the macro task, will need to execute the next time period
-
The flow chart of event cycle mechanism is as follows:
- Details are as follows:
Each time the main thread is executed, check whether it is a synchronous task or an asynchronous API
3. The asynchronous thread executes the asynchronous API. 4. The asynchronous thread executes the asynchronous API. The asynchronous callback event is put into the event queue. After the synchronization task in the hand of the main thread is finished, the main thread comes to the event queue to see if there is any task. The main thread finds that there is a task in the event queue, and then it takes out the task and executes the above process continuously
Wrong timer
In the Event Loop process, there are some hidden holes. The most typical problem is that the synchronization task is always executed first, and then the callback in the Event queue is executed. This feature directly affects the execution of the timer. Let’s think about the process we started with the 2-second timer:
The main thread executes the synchronization code
2 met setTimeout and gave it to the timer thread 3 timer thread start timing, 2 seconds to the notification event trigger thread 4 events trigger thread put the timer callback in queue, it is the end of 5 main thread asynchronous processes if have time, will take out the timer callback execution, if not the callback has been in the queue.
conclusion
The execution results of the above incorrect writing method are as follows:
-
The synchronization code is executed first (i.e. after two clicks), and setTimeout is executed last.
-
This. UpdateAge is not cleared because setTimeout is not defined when clearTimeout is executed
-
The final number of times setTimeout is executed is the number of clicks
Here’s an example: Same principle
<! DOCTYPE html><html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div></div>
<input id="inp" />
<script>
inp.addEventListener('input'.() = > {
console.log('script start');
setTimeout(function () {
console.log('---setTimeout')},5000);
Promise.resolve().then(function () {
console.log('promise1');
}).then(function () {
console.log('promise2'); })});</script>
</body>
</html>
Copy the code
Print the following: