This is the 22nd day of my participation in the August More Text Challenge
No foreword, straight to the point, let’s talk about timers!
As we know, the timers setInterval and setTimeout are two functions defined on the window
These two functions take two arguments:
- The first argument: accepts a callback function, callback
- Second argument: Indicates the number of milliseconds to delay execution. time
// Output a 1 every 100 milliseconds
setInterval(function(){
console.log(1);
},100);
// Output 1 after 100 milliseconds, only once
setTimeout(function(){
console.log(1);
},100);
Copy the code
The difference is:
- SetTimeout Indicates a timer that executes the callback function only once after the specified number of milliseconds. SetInterval, on the other hand, is a timer circulator that executes a callback every specified number of milliseconds, or an infinite number of times if the timer is not cleared
- To clear timers, setInterval corresponds to clearInterval() and setTimeout to clearTimeout().
ClearInterval and clearTimeout are also functions defined on the window that take the name of the timer and clear the corresponding timer based on that name
Note the following when using timers:
1. If the timer is created without a name, the timer cannot be cleared.
2. The timer is defined on the global object Window. The internal function this points to the window.
3. The number of milliseconds passed in setInterval will only be recognized for the first time and cannot be changed thereafter
4. SetTimeout, setInterval is an asynchronous task
For those of you who don’t know what an asynchronous task is, right?
To understand asynchrony, you need to understand the js execution mechanism
Let’s look at an example first
// What is the result of the following code
var p = new Promise(resolve= > {
console.log(4);
resolve(5);
});
function func1() {
console.log(1)}function func2() {
setTimeout(() = > {
console.log(2)}); func1();console.log(3);
p.then(resolved= > {
console.log(resolved)
}).then(() = > {
console.log(6)}); } func2();Copy the code
Answer: 4 1 3 5 6 2
I wonder if you got that right?
If the answer is correct, you have a deep understanding of the JS implementation mechanism, continue to see can review and consolidate; Don’t feel bad if you don’t know or got it wrong. The rest of this article will give you the answer
One of the things we know about JS is that it’s a single thread that can only do one thing at a time. But why single thread? In fact, it is related to its use. As a scripting language of the browser, JS is mainly used for user interaction and DOM manipulation. If you’re designed to be multi-threaded, and one thread is adding content to a DOM node, and another thread is removing that node, who does the browser listen to?
So, in order to avoid the complications of multithreading, JS was designed from the beginning to be single-threaded, which is called the core feature of the language and will not change.
In order to take advantage of the computing power of multi-core CUP, HTML5 proposes the Web Worker standard, which allows JS to create multiple threads, but the child threads are completely controlled by the main thread, and the child threads cannot manipulate DOM. Therefore, this new standard does not change the nature of js single threads.
Single threading means that all tasks need to be queued until the first one is finished before the next one can be executed. If the first task takes a long time, the second task has to wait forever. But if some tasks are slow (such as Ajax operations reading data from the network), do I still have to wait for the results to perform the latter task? That’s not good.
So, there’s an asynchronous task.
A synchronization task refers to a task that is queued to be executed on the main thread. The next task can be executed only after the first task is completed. An asynchronous task is a task that does not enter the main thread but enters the Task queue. It will only enter the main thread when the main thread notifies the task queue that an asynchronous task is ready to execute.
So in fact, JS multi-threaded implementation is through the asynchronous way to achieve
The operating mechanism is as follows:
(1) All synchronization tasks are executed on the main thread, forming a Call Stack.
(2) In addition to the main thread, there is a task queue. Whenever an asynchronous task has a result, an event is placed in the "task queue"
(3) Once all synchronization tasks in the "execution stack" are completed, the system reads the "task queue" to see what events are in it. Those corresponding asynchronous tasks then end the wait state, enter the execution stack, and start executing.
(4) The main thread repeats step 3 above.
Execution stack is used to organize JS code and ensure the orderly execution of JS code. Each time a function is called, it is pushed onto the execution stack, and the next function is called
In the second step, the asynchronous task actually runs with the help of other threads in the browser behind it
Browser kernel resident thread:
- Js engine thread
Used to interpret executing JS code, user input, network requests, etc
- GUI rendering thread
Draw the user interface, which is mutually exclusive with the JS main thread (because JS can manipulate the DOM, and thus affect the GUI rendering results)
- HTTP asynchronous network request thread
Process the user’s get, POST and other requests, and push the callback function to the task queue after the result is returned
- Timing trigger thread
SetInterval and setTimeout After the waiting period ends, the execution function is pushed to the task queue
- Browser event handler thread
The callback functions that will be executed after click, Mouse, and other interactive events occur are placed in the event queue
A task queue is a first-in, first-out data structure in which the first event is read by the main thread.
When the main thread is empty, the “task queue” is read again, but the task queue varies between host environments. Most host environments divide the task queue into macroTasks and microtasks.
Most of the macro tasks include: Script, setTimeout, setInterval, I/O, UI interaction events, and setImmediate(node.js).
Microtasks mainly include: Promise then, async await, MutaionObserver, process.nexttick (Node.js environment)
When the execution stack is cleared, the JS engine will first complete all the tasks in the microtask in sequence. If there are no microtasks, the macro task will be executed.
The reading of the main thread is essentially automatic. As soon as the stack is emptied, the first event in the “task queue” automatically enters the main thread. However, the timer first checks whether the execution time has reached the specified time, and then enters the main thread for execution, and then reads the next Event in the task queue after execution. This process is cyclic, and we call this cyclic mechanism Event Loop, namely
When the main thread runs, the heap and stack are created, and the code in the stack calls various external apis (that is, functions), which add various events (click, load, done) to the "task queue". As soon as the stack completes, the main thread reads the "task queue" and executes the corresponding callback function for those events.
Now the timer
If the second parameter of setTimeout() is set to 0, the specified callback is executed immediately after the stack is cleared (0 milliseconds).
setTimeout(function(){console.log(1); },0);
console.log(2);
Copy the code
The result is 2,1, because the system does not execute the callback function in the “task queue” until the second line is completed.
The HTML5 standard specifies that the second parameter of setTimeout() must be at least 4 milliseconds, and if it is below this value, it is automatically increased. Previously, older browsers had set the minimum interval to 10 milliseconds. In addition, DOM changes, especially those that involve page re-rendering, are usually not performed immediately, but every 16 milliseconds.
Note that setTimeout() simply inserts the event into the “task queue”, and the main thread will not execute the callback function specified in the timer until the current code (the execution stack and the first microtask) has finished executing. If the current code takes a long time, it may take a long time, so there is no guarantee that the callback will be executed at setTimeout().
Finally, come back to the question above:
// What is the result of the following code
var p = new Promise(resolve= > {
console.log(4);
resolve(5);
});
function func1() {
console.log(1)}function func2() {
setTimeout(() = > {
console.log(2)}); func1();console.log(3);
p.then(resolved= > {
console.log(resolved)
}).then(() = > {
console.log(6)}); } func2();Copy the code
perform
Step 1: Press new Promis into the stack, then execute the code inside, print 4, and execute resolve(5); Note that the new normal function executes normally and is not added to the macro task;
Step 2: Perform func2(), encounter setTimeout, and place it in the macro task;
Then func1(); Print out 1
Then the console. The log (3); Print 3
When a Promise object executes then(), this is asynchronous, it will put the callback inside the microtask and wait for it to execute. When the execution stack is cleared, it will execute console.log(Resolved) in the microtask and print out 5.
When the microtask is cleared, the macro task will be executed, that is, when setTimeout reaches the time, 2 will be agreed.
So the final answer is: 4, 1, 3, 5, 6, 2
That’s all about timers and JS execution mechanisms