Previously, we explored the working principle of JavaScript from the parsing mechanism of the JavaScript engine. Now we use a more vivid example to illustrate the execution order of JavaScript code on the page. If the working mechanism of the JavaScript engine is relatively profound because it belongs to the underlying behavior, then the execution order of the JavaScript code is more vivid, because we can intuitively feel this execution order. Of course, the execution order of the JavaScript code is more complicated, so It is also necessary to profile the JavaScript language before diving into it.
1.1 Execute JavaScript code in order of HTML document flow
First of all, readers should know that the parsing process of HTML documents in the browser is as follows: the browser gradually parses the page structure and information from top to bottom according to the document flow. JavaScript code as an embedded script should also be counted as a component of the HTML document, so the execution order of the JavaScript code during loading is also determined based on the order in which the script tag <script> appears. For example, browse the documentation page below and you'll see that the code is parsed step by step from top to bottom.
Copy the code code as follows:
<script>
alert("Top script");
</script>
<html><head>
<script>
alert("head script");
</script>
<title></title>
</head>
<body>
<script>
alert("page script");
</script>
</body></html>
<script>
alert("bottom script");
</script>
If an external JavaScript file script is imported through the src attribute of the script tag <script>, then it will also be executed in the order in which its statements appear, and the execution process is part of the document loading. Execution will not be delayed because it is an external JavaScript file. For example, move the scripts in the head and body areas of the document above to external JavaScript files, and then import them through the src attribute. Continuing to preview the page document, you will see the same order of execution.
Copy the code code as follows:
<script>
alert("Top script");
</script>
<html>
<head>
<script src="//www.VeVB.COm/head.js"></script>
<title></title>
</head>
<body>
<script src="//www.VeVB.COm/body.js"></script>
</body>
</html>
<script>
alert("bottom script");
</script>
1.2 The relationship between precompilation and execution order
In Javascript, function is the first type of Javascript. When we write a function, we are actually just creating an entity of type function.
Just like we can write it in this form:
Copy the code code as follows:
functionHello()
{
alert("Hello");
}
Hello();
varHello = function()
{
alert("Hello");
}
Hello();
In fact, they are all the same. But when we modify the functions, we will find very strange problems.
Copy the code code as follows:
<scripttype="text/javascript">
functionHello() {
alert("Hello");
}
Hello();
functionHello() {
alert("Hello World");
}
Hello();
</script>
We will see the result like this: Hello World is output twice in a row.
Rather than the Hello and Hello World we imagined.
This is because Javascript is not completely interpreted and executed in order. Instead, Javascript is "precompiled" before interpretation. During the precompilation process, defined functions will be executed first and all var variables will be created. , the default value is undefined to improve program execution efficiency.
In other words, the above piece of code is actually pre-compiled by the JS engine into this form:
Copy the code code as follows:
<scripttype="text/javascript">
varHello = function() {
alert("Hello");
}
Hello = function() {
alert("Hello World");
}
Hello();
Hello();
</script>
We can clearly see from the above code that functions are also data and variables. We can also assign (reassign) values to "functions".
Of course, in order to prevent this situation, we can also do this:
Copy the code code as follows:
<scripttype="text/javascript">
functionHello() {
alert("Hello");
}
Hello();
</script>
<scripttype="text/javascript">
functionHello() {
alert("Hello World");
}
Hello();
</script>
In this way, the program is divided into two sections, and the JS engine will not put them together.
When the JavaScript engine parses a script, it processes all declared variables and functions during precompilation.
Do the following:
1. Before execution, an operation similar to "precompilation" will be performed: first, an active object in the current execution environment will be created, and those variables declared with var will be set as attributes of the active object, but at this time, the assignment of these variables will be is undefined, and those functions defined with function are also added as properties of the active object, and their values are exactly the definition of the function.
2. During the interpretation and execution phase, when a variable needs to be parsed, it will first be searched from the active object of the current execution environment. If it is not found and the owner of the execution environment has the prototype attribute, it will be searched from the prototype chain, otherwise it will be searched. Will search according to the scope chain. When encountering a statement such as var a = ..., the corresponding variable will be assigned a value (note: the assignment of the variable is completed during the interpretation and execution phase. If the variable is used before this, its value will be undefined). Therefore, just It will appear that no error will be reported when the JavaScript interpreter executes the following script:
Copy the code code as follows:
alert(a); // return value undefined
var a =1;
alert(a); // return value 1
Since variable declarations are processed at precompilation time, they are visible to all code during execution. However, you will also see that when executing the above code, the value prompted is undefined, not 1. This is because the variable initialization process occurs during execution, not pre-compilation. During execution, the JavaScript interpreter parses the code in order. If a variable is not assigned a value in the previous line of code, the JavaScript interpreter will use the default value of undefined. Since the variable a is assigned a value in the second line, the third line of code will prompt that the value of variable a is 1, not undefined.
Similarly, in the following example, it is legal to call the function before the function is declared and can be parsed correctly, so the return value is 1.
Copy the code code as follows:
f(); // Call function, return value 1
function f(){
alert(1);
}
However, if the function is defined as follows, the JavaScript interpreter will prompt a syntax error.
Copy the code code as follows:
f(); // Call function and return syntax error
var f = function(){
alert(1);
}
This is because the function defined in the above example is only assigned to the variable f as a value. Therefore, during the pre-compilation period, the JavaScript interpreter can only process the declaration of variable f, and the value of variable f can only be pressed during the execution period. If assignments are performed sequentially, a syntax error will naturally occur, indicating that the object f cannot be found.
Bye some examples:
Copy the code code as follows:
<script type="text/javascript">
/*During the precompilation process, func is an attribute in the active object in the window environment, and the value is a function, covering the undefined value*/
alert(func); //function func(){alert("hello!")}
var func = "this is a variable"
function func(){
alert("hello!")
}
/*During execution, var was encountered and reassigned to "this is a variable"*/
alert(func); //this is a variable
</script>
Copy the code code as follows:
<script type="text/javascript">
var name = "feng"; function func()
{
/*First, assign name to undefined in the func environment, and then look for the name attribute of the active object in the func environment during execution. At this time, the value has been precompiled to undefined, so the output is undefined, not feng */
alert(name); //undefined var name = "JSF";
alert(name); //JSF
}
func();
alert(name);
//feng
</script>
Although variable and function declarations can be anywhere in the document, it is a good practice to declare global variables and functions before all JavaScript code, and to initialize and assign variables. Within a function, variables are declared first and then referenced.
1.3 Execute JavaScript code in blocks
The so-called code blocks are code segments separated by <script> tags. For example, the two <script> tags below represent two JavaScript code blocks.
Copy the code code as follows:
<script>
// JavaScript code block 1
var a =1;
</script>
<script>
// JavaScript code block 2
function f(){
alert(1);
}
</script>
When the JavaScript interpreter executes a script, it executes it in blocks. In layman's terms, if the browser encounters a <script> tag when parsing the HTML document stream, the JavaScript interpreter will wait until the code block is loaded, first pre-compile the code block, and then execute it. After execution, the browser continues to parse the HTML document stream below, and the JavaScript interpreter is ready to process the next block of code.
Since JavaScript is executed in blocks, if you call a variable or function declared in a subsequent block in a JavaScript block, a syntax error will be prompted. For example, when the JavaScript interpreter executes the following code, it will prompt a syntax error, showing that variable a is undefined and object f cannot be found.
Copy the code code as follows:
<script>
// JavaScript code block 1
alert(a);
f();
</script>
<script>
// JavaScript code block 2
var a =1;
function f(){
alert(1);
}
</script>
Although JavaScript is executed in blocks, different blocks belong to the same global scope, which means that variables and functions between blocks can be shared.
1.4 Use the event mechanism to change the order of JavaScript execution
Because JavaScript processes code in chunks and follows the parsing order of the HTML document flow, you will see such syntax errors in the above example. But when the document stream is loaded, such an error will not occur if it is accessed again. For example, if the code that accesses the variables and functions in the second block of code is placed in the page initialization event function, there will be no syntax errors.
Copy the code code as follows:
<script>
// JavaScript code block 1
window.onload = function(){ // Page initialization event handling function
alert(a);
f();
}
</script>
<script>
// JavaScript code block 2
var a =1;
function f(){
alert(1);
}
</script>
For security reasons, we generally only allow JavaScript code execution after the page is initialized. This can avoid the impact of network speed on JavaScript execution, and also avoid the restrictions on JavaScript execution caused by HTML document flow.
Notice
If there are multiple windows.onload event handlers in a page, only the last one is valid. To solve this problem, you can put all scripts or calling functions in the same onload event handler, for example:
Copy the code code as follows:
window.onload = function(){
f1();
f2();
f3();
}
And in this way, the execution order of functions can be changed by simply adjusting the order of calling functions in the onload event handler.
In addition to page initialization events, we can also change the execution order of JavaScript code through various interactive events, such as mouse events, keyboard events, clock triggers, etc. For detailed explanation, please refer to Chapter 14.
1.5 Execution order of JavaScript output scripts
In JavaScript development, the write() method of the document object is often used to output JavaScript scripts. So how are these dynamic output scripts executed? For example:
Copy the code code as follows:
document.write('<script type="text/javascript">');
document.write('f();');
document.write('function f(){');
document.write('alert(1);');
document.write('}');
document.write('</script>');
Running the above code, we will find that: the document.write() method first writes the output script string to the document location where the script is located. After parsing the content of the document where document.write() is located, the browser continues to parse document.write () output content, and then parse the subsequent HTML documents in order. In other words, the code string output by the JavaScript script will be executed immediately after output.
Please note that the JavaScript script string output using the document.write() method must be placed in the <script> tag that is output at the same time, otherwise the JavaScript interpreter will not be able to recognize these legal JavaScript codes and will be displayed as an ordinary string. in the page document. For example, the following code will display the JavaScript code instead of executing it.
Copy the code code as follows:
document.write('f();');
document.write('function f(){');
document.write('alert(1);');
document.write(');');
However, there are certain risks in outputting and executing scripts through the document.write() method, because different JavaScript engines execute them in different orders, and bugs may occur in different browsers during parsing.
Ø Problem 1: The variables or functions declared in the external JavaScript file imported through the document.write() method cannot be found. For example, look at the sample code below.
Copy the code code as follows:
document.write('<script type="text/javascript" src="//www.VeVB.COm/test.js">
</script>');
document.write('<script type="text/javascript">');
document.write('alert(n);'); // IE prompts that variable n cannot be found
document.write('</script>');
alert(n+1); // All browsers will prompt that variable n cannot be found
The code of the external JavaScript file (test.js) is as follows:
Copy the code code as follows:
var n = 1;
When tested in different browsers, you will find a syntax error and variable n cannot be found. In other words, if you access in a JavaScript code block the variables contained in the external JavaScript file imported in the script output by using the document.write() method in this code block, a syntax error will be displayed. At the same time, if in the IE browser, not only in the script, but also in the output script, it will prompt that the output variable imported into the external JavaScript file cannot be found (the expression is a bit long and convoluted, readers who do not understand can try to run the above code can be understood).
Ø Question 2: Different JavaScript engines have slightly different execution orders for output external import scripts. For example, look at the sample code below.
Copy the code code as follows:
<script type="text/javascript">
document.write('<script type="text/javascript" src="http://shaozhuqing.com/test1.js">
</script>');
document.write('<script type="text/javascript">');
document.write('alert(2);')
document.write('alert(n+2);');
document.write('</script>');
</script>
<script type="text/javascript">
alert(n+3);
</script>
The code for the external JavaScript file (test1.js) is shown below.
Copy the code code as follows:
var n = 1;
alert(n);
The execution sequence in IE browser is shown in Figure 1-6.
Figure 1-6 The execution sequence and syntax errors prompted by IE 7 browser
The execution sequence in browsers that comply with DOM standards is different from that in IE browsers, and there are no syntax errors. Figure 1-7 shows the execution sequence in Firefox 3.0 browser.
Figure 1-7 Firefox 3 browser execution sequence and syntax errors prompted
Solve the different execution orders of different browsers and possible bugs. We can put all external files imported using the output script in independent code blocks, so that this problem can be avoided according to the execution order of the JavaScript code blocks introduced above. For example, for the above example, you can design it like this:
Copy the code code as follows:
<script type="text/javascript">
document.write('<script type="text/javascript" src="//www.VeVB.COm/test1.js"></script>');
</script>
<script type="text/javascript">
document.write('<script type="text/javascript">');
document.write('alert(2);') ; // Tip 2
document.write('alert(n+2);'); // Tip 3
document.write('</script>');
alert(n+3); // Tip 4
</script>
<script type="text/javascript">
alert(n+4); // Tip 5
</script>
In this way, the above code can be executed in order in different browsers, and the output order is 1, 2, 3, 4 and 5. The reason for the problem is: a contradiction between the output imported script and the current JavaScript code block. If output separately, there will be no conflict.