Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the sequential execution of javascript

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains the "javascript sequence execution is how", the article explains the content is simple and clear, easy to learn and understand, the following please follow the editor's ideas slowly in depth, together to study and learn "javascript sequence execution is how" it!

Javascript is executed sequentially. JavaScript is a single-threaded language, and the execution order is top-down, that is, during the execution of the code, another piece of code must wait until the execution of the current code is complete.

The operating environment of this tutorial: windows7 system, javascript1.8.5 version, Dell G3 computer.

Sequential execution Mechanism of JavaScript

1. Single threaded JavaScript

As we all know, JavaScript is a single-threaded language, and the order of execution is top-down. JavaScript does not have the concept of multithreading, all programs are executed in a single thread in turn. That is, during the execution of the code, another piece of code that wants to be executed must wait until the execution of the current code is complete.

Note that JavaScript runs on only one thread, which does not mean that the JavaScript engine has only one thread. In fact, the JavaScript engine has multiple threads, and a single script can only run on one thread (called the main thread). The other threads cooperate in the background.

So why is js single-threaded and not multithreaded? Isn't multithreading more efficient?

The reason why JavaScript uses single thread rather than multi-thread has something to do with its use. as a web scripting language, the main purpose of JavaScript is to interact with users and operate DOM.

If the JavaScript has two threads at the same time, one thread adds content to the DOM node of the web page, and the other thread deletes the node, which thread should the browser follow? Is there still a locking mechanism?

JavaScript has been single-threaded since its birth, because it doesn't want browsers to get too complicated, because multiple threads need to share resources and possibly modify each other's running results, which is too complicated for a web scripting language.

So, to avoid complexity, JavaScript starts with a single thread, which has become a core feature of the language and will not change in the future.

The advantage of this model is that it is relatively simple to implement and the execution environment is relatively simple; the downside is that as long as there is a task that takes a long time, the following tasks must wait in line, which will delay the execution of the whole program.

Common browsers are unresponsive (fake death), often because a piece of JavaScript code runs for a long time (such as an endless loop), resulting in the entire page stuck in this place, other tasks can not be performed.

The JavaScript language itself is not slow, it is slow to read and write external data, such as waiting for the Ajax request to return the result. At this time, if the other server is slow to respond, or the network is not smooth, it will cause the script to stagnate for a long time.

If the queue is due to a large amount of computation, CPU is too busy, but most of the time CPU is idle because the IO operation (input and output) is very slow (for example, the Ajax operation reads data from the network), so you have to wait for the result to come out and then execute it.

The designers of the JavaScript language realized that at this point, CPU can completely ignore the IO operation, suspend the waiting task and run the next task first. Wait until the IO operation returns the result, then go back and continue the pending task. This mechanism is the "event loop" mechanism (Event Loop) adopted within JavaScript.

Although the single-threaded model poses great restrictions on JavaScript, it also gives it an advantage that other languages do not have. If used well, JavaScript programs will not be blocked, which is why Node can cope with heavy traffic with very few resources.

In order to take advantage of the computing power of multicore CPU, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but child threads are completely controlled by the main thread and are not allowed to operate DOM. Therefore, this new standard does not change the nature of JavaScript single-threading.

Now let's look at a piece of code.

Function fn () {console.log ('start'); setTimeout () = > {console.log (' setTimeout');}, 0); console.log ('end');} fn () / / output start end setTimeout

Since the order of execution of JavaScript is top-down, why is the order of execution of the above code disrupted?

Because there are two execution modes of JavaScript: synchronous and asynchronous

Synchronization and asynchronism of 2.JavaScript

All tasks in the program can be divided into two categories: synchronous tasks (synchronous) and asynchronous tasks (asynchronous).

What is synchronous and asynchronous? How are synchronization and asynchronism implemented?

Synchronization tasks: those tasks that are not suspended by the engine and are queued on the main thread. Only when the previous task is completed can the latter task be carried out.

Asynchronous tasks: those tasks that are put aside by the engine and do not enter the main thread but enter the task queue. An asynchronous task (in the form of a callback function) will be executed in the main thread only if the engine thinks it can be executed (for example, the Ajax operation gets the result from the server). (generally speaking, a task will not enter the main thread until the "task queue" notifies the main thread that an asynchronous task can be executed. )

The code that comes after the asynchronous task will run immediately without waiting for the asynchronous task to finish, that is, the asynchronous task does not have a "blocking" effect.

For example, Ajax operations can be treated as synchronous or asynchronous tasks, as determined by the developer. If it is a synchronous task, the main thread waits for the Ajax operation to return the result, and then executes; if it is an asynchronous task, the main thread executes directly after issuing the Ajax request, and then executes the corresponding callback function when the Ajax operation has a result.

Js contains many functions that create asynchrony, such as:

SeTimeout,setInterval,dom event, ajax,Promise,process.nextTick and other functions

3. Task queues and event loops

When JavaScript runs, in addition to a running main thread, the engine also provides a task queue (task queue) that contains a variety of asynchronous tasks that need to be handled by the current program. (in fact, depending on the type of asynchronous task, there are multiple task queues. For ease of understanding, it is assumed that there is only one queue. )

First, the main thread performs all synchronization tasks. When the synchronous tasks are all executed, you will look at the asynchronous tasks in the task queue.

If the condition is met, the asynchronous task reenters the main thread and starts execution, and it becomes a synchronous task. When the execution is finished, the next asynchronous task enters the main thread to begin execution. Once the task queue is empty, the program ends execution.

Asynchronous tasks are usually written as callback functions. Once the asynchronous task re-enters the main thread, the corresponding callback function is executed. If an asynchronous task does not have a callback function, it will not enter the task queue, that is, it will not re-enter the main thread because no callback function is used to specify the next step.

Because of the single thread, the code executes from the top down, and all the code is executed on the execution stack

Encounters an asynchronous function to add a callback function to a task queue

When the code in the execution stack is executed, it loops the function in the task queue

Put the functions in the task queue into the execution stack to execute

To and fro is called an event loop.

How does the JavaScript engine know if an asynchronous task has a result and whether it can enter the main thread? The answer is that the engine is constantly checking, over and over again, as soon as the synchronous task is finished, the engine will check to see if the suspended asynchronous tasks can enter the main thread. This loop checking mechanism is called an event loop.

With this analysis, the above code is reasonably explained.

Take a look at this code again:

Function fn () {setTimeout () = > {console.log ('a');}, 0); new Promise ((resolve) = > {console.log ('b'); resolve ();}). Then () = > {console.log ('c')});} fn () / / b c a

4.Promise and async execute immediately

The asynchronism in Promise is reflected in then and catch, so the code written in Promise is executed immediately as a synchronous task.

In async/await, the code is also executed immediately before the emergence of await. So what happened when await appeared?

What did await do after that?

Many people think that await will wait for the following expression to be executed before continuing to execute the following code, but await is actually a sign to give up the thread. The expression after await is executed first, adding the code after await to the microtask, and then jumping out of the entire async function to execute the following code.

Whether the code behind the await is synchronous or asynchronous, await always takes time to execute from right to left, first executing the code on the right, and then finding the await keyword after execution, so let the thread out and block the code.

Because async await itself is the grammatical sugar of promise+generator. So the code behind await is microtask.

For example:

Async function async1 () {console.log ('async1 start'); await async2 (); console.log (' async1 end');}

Equivalent to

Async function async1 () {console.log ('async1 start'); Promise.resolve (async2 ()). Then () = > {console.log (' async1 end');})}

5. Macro task and micro task

The two tasks are in the macro queue and the micro queue in the task queue.

The macro task queue and the micro task queue form the task queue

The task queue puts the task into the execution stack for execution

Macro task

Macro queue, macrotask, also known as tasks.

The callback of the asynchronous task enters the macro task queue in turn and waits for it to be called later.

Macro tasks generally include:

Overall code script

SetTimeout

SetInterval

SetImmediate (unique to Node)

RequestAnimationFrame (unique to the browser)

I/O

UI rendering (unique to the browser)

Micro task

Micro queue, microtask, also known as jobs.

The callback of the asynchronous task will enter the micro task queue in turn, waiting for it to be called later.

Microtasks generally include:

Process.nextTick (unique to Node)

Promise

Object.observe

MutationObserver

1. Execute global Script synchronous code, some of which are synchronous statements and some are asynchronous statements (such as setTimeout, etc.).

two。 After the global Script code is executed, the execution stack Stack is cleared.

3. First, the callback task at the head of the queue is taken from the micro-task queue and executed in the execution stack Stack. After execution, the length of the micro-queue is reduced by 1.

4. Continue to loop out the task in the micro-queue, put it into the execution stack Stack, and so on, until the micro-task is finished. Note that if a microtask is generated during the execution of the microtask, it will be added to the end of the microqueue and will also be called for execution during this cycle.

5. When all the micro-tasks in the micro-queue are finished, the micro-queue is listed as an empty queue and the execution stack Stack is empty.

6. Take the tasks from the macro queue and put them into the execution stack Stack to execute.

7. When the execution is complete, the execution stack Stack is empty.

8. Repeat steps 3-7.

The above is the completed * event loop

6. Face to face test

Now let's analyze the initial interview question.

Async function async1 () {console.log ('async1 start'); await async2 (); console.log (' async1 end');} async function async2 () {console.log ('async2');} console.log (' script start'); setTimeout (function () {console.log ('setTimeout');}, 0) async1 (); new Promise (function (resolve) {console.log (' promise1'); resolve () ) .then (function () {console.log ('promise2');}); console.log (' script end'); / * script startasync1 startasync2promise1script endasync1 endpromise2setTimeout*/

Let's analyze the whole process:

1. First, the event loop starts with the macro task (macrotask) queue, where there is only one script (overall code) task in the macro task queue; when a task source (task source) is encountered, the task is first distributed to the corresponding task queue.

two。 Then we see that we first define two async functions, then look down, and then encounter a console statement that outputs script start directly. After the output, the script task continues to execute and encounters setTimeout, which, as a macro service source, first distributes its tasks to the corresponding queue.

The 3.script task continues, executing the async1 () function, and as I said earlier, the code in the async function before await is executed immediately, so the async1 start is output immediately.

When await is encountered, the expression following await is executed, so immediately output async2, then add the code after await, namely console.log ('async1 end'), to the Promise queue in microtask, and then jump out of the async1 function to execute the following code.

The 4.script task continues and encounters a Promise instance. Because functions in Promise are executed immediately, subsequent .then are distributed to microtask's Promise queue. So the promise1 is output first, and then the resolve is executed to assign the promise2 to the corresponding queue.

The 5.script task continues to execute, with only one sentence outputting script end, and the global task is finished.

According to the above, after each execution of a macro task, it is checked to see if there is a Microtasks;. If so, execute Microtasks until the Microtask Queue is cleared.

Therefore, after the execution of the script task, the search starts to empty the micro-task queue. At this point, there are two tasks in the Promise queue, async1 end and promise2, so the async1 end,promise2 is output sequentially. When all the Microtasks is executed, the first round of the loop is over.

6. The second cycle still starts with the macro task queue. At this point, there is only one setTimeout in the macro task, just take out the direct output, and the whole process is over.

Let's have a slightly more complicated code.

Function fn () {console.log (1); setTimeout () = > {console.log (2); Promise.resolve (). Then (() = > {console.log (3);});}, 0); new Promise ((resolve, reject) = > {console.log (4); resolve (5) ) .then (data = > {console.log (data);}); setTimeout (() = > {console.log (6);}, 0); console.log (7);} fn (); / /

Process reappearance

1. Execute function synchronization statement

Step1

Console.log (1)

Execution stack: [console]

Macro tasks: []

Micro tasks: []

Print the results:

one

Step2

SetTimeout (() = > {/ / this callback function called callback1,setTimeout belongs to the macro task, so put it in the macro queue console.log (2); Promise.resolve () .then (() = > {console.log (3)});})

Execution stack: [setTimeout]

Macro task: [callback1]

Micro tasks: []

Print the results:

one

Step3

New Promise ((resolve, reject) = > {/ / Note, here is the synchronous execution of console.log (4); resolve (5)}). Then ((data) = > {/ / this callback function called callback2,promise is a micro task, so put it in the micro queue console.log (data);})

Execution stack: [promise]

Macro task: [callback1]

Micro tasks: [callback2]

Print the results:

one

four

Step4

SetTimeout (() = > {/ / this callback function called callback3,setTimeout belongs to the macro task, so put it in the macro queue console.log (6);})

Execution stack: [setTimeout]

Macro task: [callback1, callback3]

Micro tasks: [callback2]

Print the results:

one

four

Step5

Console.log (7)

Execution stack: [console]

Macro task: [callback1, callback3]

Micro tasks: [callback2]

Print the results:

one

four

seven

two。 After the execution of the synchronization statement, take the task out of the micro-queue and execute it until the micro-queue is empty.

Step6

Console.log (data) / / where data is the success parameter of Promise is 5

Execution stack: [callback2]

Macro task: [callback1, callback3]

Micro tasks: []

Print the results:

one

four

seven

five

3. Here there is only one task in the micro queue. After execution, we start to fetch the task from the macro queue for execution.

Step7

Console.log (2)

Execution stack: [callback1]

Macro task: [callback3]

Micro tasks: []

Print the results:

one

four

seven

five

two

But when I was executing callback1, I encountered another Promise,Promise. After the asynchronous execution, I registered another callback4 function in the micro queue.

Step8

Promise.resolve () .then (() = > {/ / this callback function called callback4,promise is a micro task, so put it in the micro queue console.log (3);})

Execution stack: [Promise]

Macro task: [callback3]

Micro tasks: [callback4]

Print the results:

one

four

seven

five

two

4. Take out a macro task after macrotask execution, and then go to the micro task queue microtask queue to take it out and execute it in turn

Step9

Console.log (3)

Execution stack: [callback4]

Macro task: [callback3]

Micro tasks: []

Print the results:

one

four

seven

five

two

three

5. After all the execution of the micro queue, go to the macro queue to get the first task for execution.

Step10

Console.log (6)

Execution stack: [callback3]

Macro tasks: []

Micro tasks: []

Print the results:

one

four

seven

five

two

three

six

6. After all the above execution is completed, the execution stack, macro queue and * * micro queue * * are all empty.

Execution stack: []

Macro tasks: []

Micro tasks: []

Print the results:

one

four

seven

five

two

three

six

Thank you for your reading, the above is the content of "what is the sequential execution of javascript". After the study of this article, I believe you have a deeper understanding of how the sequential execution of javascript is, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report