script tag
Top-level objects are shared between script tags.
<script> var a = 1; </script> <script> console.log(a); // 1 </script>
But the hoisting mechanism of global variable scope does not apply in these boundaries:
<script> foo(); </script> <script> function foo() {<!-- --> console.log('foo'); } </script>
But the following two pieces of code are fine:
<script> foo(); function foo() {<!-- --> console.log('foo'); } </script>
<script> function foo() {<!-- --> console.log('foo'); } </script> <script> foo(); </script>
If an error occurs in the code in the script (whether it is inline code or external code), it will stop like a stand-alone JS program, but subsequent code in the script will still continue to run without being affected.
There is one difference between inline code and code in external files, that is, the string cannot appear in inline code. Once it appears, it is considered the end of the code block. So be very careful with code like the following:
<script> var code = "<script>alert('Hello World')</script>"; </script>
The above code seems to have no problem, but in the string constant will be treated as an end tag, thus causing an error.
Common workarounds are:
'</' + 'script>';
Using the escape character \
also works:
<script> function sayScript() {<!-- --> console.log('<\/script>'); // Use escape characters } </script>
Another thing to note is that we parse the code in the external file based on the character set attribute of the code file, while the inline code uses the character set of the page file in which it is located.
The script tag of inline code does not have a charset attribute.
Attributes of the script tag
src
: Optional. Specify an external script file.async
: Optional. Indicates an asynchronous loading script, which will be executed immediately after loading is completed. Only valid for external script files.defer
: Optional. Indicates that the script is loaded asynchronously and is executed after the document is completely parsed and displayed. Only valid for external script files.crossorigin
: Optional. Configure CORS (Cross-Origin Resource Sharing) settings for related requests. CORS is not used by default.crossorigin="anonymous"
indicates that the credentials flag will not be set for file requests.crossorigin="use-credentials"
indicates that file requests will have the credentials flag set, meaning that outbound requests will include credentials.integrity
: Optional. Allows comparison of received resources with specified cryptographic signatures to verify subresource integrity (SRI). If the signature of the received resource does not match the signature specified by this attribute, the page will report an error and the script will not be executed. This attribute can be used to ensure that a Content Delivery Network (CDN) does not serve malicious content.
Usage of script tag
The element using the
src
attribute should no longer be used in the and
tags Contains other JS code. If both are provided, the browser will only download and execute the external script file, ignoring inline code.
Much like the element, the
element's
src
attribute can be a complete URL, and the resource pointed to by this URL can be Not in the same domain as the HTML page that contains it.
When the browser parses this resource, it will send a GET request to the path specified by the src attribute to obtain the corresponding resource, assuming it is a JS file. This initial request is not restricted by the browser's same-origin policy, but the JS returned and executed is. Of course, this request is still subject to the HTTP/HTTPS protocol of the parent page.
Code from an external domain is loaded and interpreted as part of the page that loads it. This capability allows us to distribute JS across different domains. However, be careful when referencing JS files hosted on someone else's server, as a malicious programmer may replace the file at any time. When including JS files from external domains, make sure that you own the domain or that it is a trusted source. The integrity
attribute of the tag is a weapon against this problem.
Regardless of the included code, browsers will interpret in the order in which they appear on the page, provided they do not use
defer
and async
attribute. The code of the second element must be interpreted before the code of the first
element is interpreted. The third one must wait for the second interpretation. Finished, and so on.
script tag position
The script tag will block the parsing of HTML, so try to place it at the bottom of HTML to avoid affecting the first screen rendering of the page.
When the browser encounters a script tag, it will pause parsing the HTML document and first execute the JS code in the script tag, because the JS code may modify the structure or content of the HTML. This will cause the rendering of the page to be delayed, and the user will see a blank page. The browser will not continue to parse the HTML document and render the page until the script tag is executed. Therefore, in order to improve the user experience, we should try to place the script tag at the bottom of the HTML, so that the browser can first parse and render the first-screen content of the page, and then execute the JS code in the script tag.
Suppose we have an inline JS code that performs some time-consuming logic when the page loads. We place it within the head tag, such as:
<html> <head> <!-- Inline JS placed within the head tag will block HTML parsing and page rendering --> <script> // Some time-consuming logic for (var i = 0; i < 1000000000; i + + ) {<!-- -->} </script> </head> <body> <!-- Page content --> <h1>Hello World</h1> </body> </html>
In this case, when the user opens this page, he will see a blank page, and he will not see "Hello World" until the inline JS is executed.
If we put the inline JS at the bottom of the body tag, like:
<html> <head> </head> <body> <!-- Page content --> <h1>Hello World</h1> <!-- Inline JS is placed at the bottom of the body tag and will not block HTML parsing and page rendering --> <script> // Some time-consuming logic for (var i = 0; i < 1000000000; i + + ) {<!-- -->} </script> </body> </html>
In this case, when the user opens this page, he will first see "Hello World" and then wait for the inline JS to complete execution. This improves user experience.
Delay script execution
Setting the defer
attribute on the element is equivalent to telling the browser to download immediately but delay execution. The
defer
attribute indicates that the script will be delayed until the entire page is parsed before running.
<!DOCTYPE html> <html> <head> <title>Example HTML Page</title> <script defer src="example1.js"></script> <script defer src="example2.js"></script> </head> <body> <!-- Here is the page content --> </body> </html>
Although the elements in this example are included in the page's
, they will be parsed by the browser to the closing
tag will be executed. The HTML5 specification requires that scripts should be executed in the order in which they appear, so the first deferred script will execute before the second deferred script, and both will execute before the DOMContentLoaded event. However, in practice, deferred scripts may not always be executed sequentially or before the DOMContentLoaded event, so it is best to only include one such script.
As mentioned before, the defer
attribute is only valid for external script files.
Execute script asynchronously
Setting the async
attribute on the element will tell the browser to start downloading immediately. However, unlike
defer
, scripts marked async
are not guaranteed to be executed in the order in which they appear, for example:
<!DOCTYPE html> <html> <head> <title>Example HTML Page</title> <script async src="example1.js"></script> <script async src="example2.js"></script> </head> <body> <!-- Here is the page content --> </body> </html>
In this example, the second script may be executed before the first script. So the point is that there are no dependencies between them. The purpose of adding the async
attribute to a script is to tell the browser that it does not have to wait for the script to be downloaded and executed before loading the page, nor does it need to wait for the asynchronous script to be downloaded and executed before loading other scripts. Because of this, asynchronous scripts should not modify the DOM during loading.
Asynchronous scripts are guaranteed to be executed before the page's load event, but may be before or after DOMContentLoaded.
Dynamic loading script
const script = document.createElement('script'); script.src = 'gibberish.js'; document.head.appendChild(script);
The request is not sent until the HTMLElement element is added to the DOM and this code is executed.
By default, dynamically created elements are loaded asynchronously, equivalent to adding the
async
attribute. If you want to unify the loading behavior of dynamic scripts, you can explicitly set it to load synchronously:
const script = document.createElement('script'); script.src = 'gibberish.js'; script.async = false; document.head.appendChild(script);
Resources obtained this way are not visible to browser preloaders. This can severely impact their priority in the resource acquisition queue. Depending on how the application works and how it is used, this approach can severely impact performance. To let the preloader know about the existence of these dynamic request files, you can declare them explicitly in the document header:
<link rel="preload" href="gibberish.js" />