Permanent thread
The browser’s resident threads are:
- Js engine threads (interpret executing JS, user input, network requests)
- GUI thread (draws the user interface and is mutually exclusive with the JS main thread)
- HTTP network request thread (processing users’ GET, POST and other requests, etc., and pushing the callback function to the task queue after the result is returned)
- Timing trigger thread (setTimeout, setInterval after waiting time to push the execution function into the task queue)
- Browser event processing thread (putting click, Mouse, and other interactive events into an event queue after they occur)
Most browsers have these five threads, which are coordinated through the UI main thread.
Js engine threads and GUI threads are mutually exclusive: JS can manipulate DOM elements and affect GUI rendering results, so JS engine threads and GUI rendering threads are mutually exclusive. This means that while the js engine thread is running, the GUI rendering thread will be frozen.
Js single-threaded
JavaScript is run on a single thread and can be executed asynchronously. In general, such single-threaded and asynchronous languages are event-driven, and browsers provide such an environment for JavaScript.
The principle expressed in the figure above:
- Synchronous and asynchronous tasks go to different execution “places”, synchronous tasks go to the main thread (execution stack) and asynchronous tasks go to the Event Table and register functions
- The Event Table moves this function to the Event Queue when the specified task is completed.
- After the tasks in the main thread are executed, the Event Queue will read the corresponding function and enter the main thread for execution
This process is repeated over and over again, known as Event Loop. Event polling is closely related to macro and micro tasks.
The timer
SetTimeout is not executed directly after the waiting time expires, but enters a task queue in the browser first. The tasks in the task queue are invoked after the synchronization queue ends. SetTimeout (function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) : setTimeout(function(){},0) But 0ms is actually unattainable, and according to THE HTML standard, the minimum is 4ms. In addition, if the main js thread execution time is too long, it will also wait for the main thread to complete, so the wait time of this function is more than 0ms. SetInterval is to place tasks in an Event Queue at intervals, using the same execution mechanism as setTimeout.
Macro tasks & micro tasks
In an event loop, asynchronous events return results that are placed in a task queue. However, depending on the type of asynchronous event, the event can actually be queued to the corresponding macro or microtask queue. And when the current stack is empty, the main thread checks for events in the microtask queue. If not, fetch an event from the macro task queue and add the corresponding event back to the current stack. If so, the queue will execute the corresponding callback until the microtask queue is empty, then fetch the first event from the macro task queue, and add the corresponding callback to the current stack. And so on and so on and so on.
Macro task
Common macro tasks: I/O, setTimeout, setInterval, setImmediate, requestAnimationFrame
Micro tasks
Common micro tasks: process. NextTick (), MutationObserver, Promise. Then/catch/finally
[Task 1] Add macro tasks and micro tasks to the main thread
console.log('-------start--------');
setTimeout(() = > {
console.log('setTimeout');
}, 0);
new Promise((resolve, reject) = > {
for (let i = 0; i < 5; i++) {
console.log(i);
}
resolve()
}).then(() = > {
console.log('Promise instance callback executes successfully ')})console.log('-------end--------');
Copy the code
Order of execution:
- Execute the main thread first
console.log('-------start--------')
And then the nextsetTimeout
To execute the macro task in the next loop - Then execute the main thread
Promise
The code is printed separately0, 1, 2, 3, 4
And then the next.then
Is a microtask, which is executed immediately after the macro task in this loop completes - Then continue to execute the last of the main thread
console.log('-------end--------')
- Perform microtasks
Promise.then
To printConsole. log('Promise instance callback successfully executed ')
- Executing macro tasks
setTimeout
To printconsole.log('setTimeout')
Output result:
-- -- -- -- -- -- -- start -- -- -- -- -- -- -- - 0 1 2 3 4 -- -- -- -- -- -- -- end -- -- -- -- -- -- -- -- Promise instance setTimeout success callback executionCopy the code
[Task 2] Create a micro-task in a micro-task
setTimeout(() = > console.log(4))
new Promise(resolve= > {
resolve()
console.log(1)
}).then(() = > {
console.log(3)
Promise.resolve().then(() = > {
console.log('before timeout')
}).then(() = > {
Promise.resolve().then(() = > {
console.log('also before timeout')})})})console.log(2)
Copy the code
Order of execution:
setTimeout
It’s a macro task, put it in the next loop- perform
Promise
In the code, printconsole.log(1)
- Continue to execute the main JS code and print
console.log(2)
- Enter the
Promise.then()
Microtasks, printingconsole.log(3)
Continue to execute the containedPromise
To printconsole.log('before timeout')
And continue to perform its microtasks.then()
To printconsole.log('also before timeout')
- Proceed to the next loop, execute
setTimeout
Macro task, printconsole.log(4)
Output result:
1
2
3
before timeout
also before timeout
4
Copy the code
[Task 3] Create a micro task in a macro task
// setTimeout-A
setTimeout(() = > {
console.log('timer_1');
// setTimeout-C
setTimeout(() = > {
console.log('timer_3')},0)
new Promise(resolve= > {
resolve()
console.log('new promise')
}).then(() = > {
console.log('promise then')})},0)
// setTimeout-B
setTimeout(() = > {
console.log('timer_2')},0)
console.log('========== Sync queue ==========')
Copy the code
Order of execution:
- I’m going to execute the main thread JS, the first few
setTimeout
Put it in the next cycle,console.log('========== Sync queue ==========')
executed - perform
setTimeout-A
To printconsole.log('timer_1')
, new Promise code, printconsole.log('new promise')
, proceed to execute its microtask code, printconsole.log('promise then')
- perform
setTimeout-B
To printconsole.log('timer_2')
- perform
setTimeout-C
To printconsole.log('timer_3')
Output result:
========== Sync queue ==========
timer_1
new promise
promise then
timer_2
timer_3
Copy the code
[Task 4] Create a macro task in a micro task
new Promise((resolve) = > {
console.log('new Promise(macro task 1)');
resolve();
}).then(() = > {
// Microtask 1
console.log('micro task 1');
setTimeout(() = > { // Macro task 3
console.log('macro task 3');
}, 0)})setTimeout(() = > { // Macro task 2
console.log('macro task 2');
}, 1000)
console.log('========== Sync queue(macro task 1) ==========');
Copy the code
Order of execution:
- Execute the main thread js first
new Promise
The code inconsole.log('new Promise(macro task 1)')
- Continue to execute the main thread, encountered
setTimeout
Move to the next loop and continueconsole.log('========== Sync queue(macro task 1) ==========')
- Perform microtasks
Promise.then()
To printconsole.log('micro task 1')
- Continue to execute the macro task under the microtask
setTimeout
To printconsole.log('macro task 3')
- Execute the main thread
setTimeout
To printconsole.log('macro task 2')
Output result:
new Promise(macro task 1)
========== Sync queue(macro task 1) ==========
micro task 1
macro task 3
macro task 2
Copy the code
[Task 5] Synthesis
console.log('开始');
new Promise(resolve= > {
console.log('Console. log for Promise1 in main thread');
resolve();
}).then(() = > {
console.log('console.log for promise1.then () in main thread');
setTimeout(() = > {
console.log('setTimeout for promise.then () in the main thread');
}, 0);
})
console.log('console.log in main thread');
setTimeout(() = > {
console.log('Console. log1 for setTimeout in main thread');
new Promise(resolve= > {
console.log('Promise of setTimeout in the main thread');
resolve();
}).then(() = > {
console.log('setTimeout promise.then () in the main thread');
})
console.log('Console. log2 for setTimeout in main thread');
setTimeout(() = > {
console.log('setTimeout of setTimeout in the main thread');
}, 0);
}, 0);
new Promise(resolve= > {
console.log('Console. log for Promise2 in main thread');
resolve();
}).then(() = > {
console.log('console.log for promise2.then () in main thread');
})
console.log('the end');
Copy the code
Output result:
Log of the Promise1 main thread console.log of the Promise2 main thread Ends console.log of the promise1.then () main thread Console. log of setTimeout console.log1 of setTimeout Promise of setTimeout console.log2 of setTimeout SetTimeout setTimeout of setTimeout in the main thread promise.then () setTimeout of promise.then () setTimeout of setTimeout in the main threadCopy the code