preface
We usually “move bricks” only focus on the business code, the page script is now automatically assembled by Webpack for us, may ignore some details of the page script.
Here are a few simple questions about script tags to test for yourself:
- What’s the difference between putting a script tag in a header and a body?
- What do defer and async properties in script do?
- Will the different loading times of multiple scripts affect their execution order?
- What do document.ready and window.load do in script loading?
- What is dynamic script loading?
It doesn’t matter if I don’t quite understand, I must admit that I have been doing this for so many years and I am still hazy (without specific practice). The following will help you clear up these concepts from a simple demo.
The demo illustrates
Using KOA to start a simple server service, through koa-static implementation of the resource file load.
const path = require('path');
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
await lazyLoadScript(ctx.path); await static(path.join(__dirname, 'public'))(ctx, next); }); app.listen(3000); Copy the code
Use setTimeout to simply implement a lazy loading function, which is used to simulate the scenario where js scripts load slowly:
function lazyLoadScript(path, time = 3000) {
return new Promise((resolve, reject) = > {
try {
// js files will be deliberately delayed by 3 seconds
if (/\/js\/test\d+\.js/.test(path)) {
console.log(Intercept `${path}.${time}Return 'after seconds); setTimeout((a)= > { console.log(` response${path}`); resolve(true); }, time); } else { resolve(true); } } catch (err) { reject(err); } }); } Copy the code
Simple HTML:
<html lang="en">
<head>
<title>Script loading mechanism</title>
</head>
<body> <h2>Script loading mechanism</h2> </body> </html> Copy the code
I’ll change the HTML and lazy loading logic to illustrate the concepts, so let’s get started.
The location of the script on the page
A script is usually placed in a header or body tag, but that position will have a different effect on page loading.
In the header
<head>
<title>Script loading mechanism</title>
<script src='/js/test1.js'></script>
<script src='/js/test2.js'></script>
<script src='/js/test3.js'></script>
</head> Copy the code
You can see the HTML loading in the first place, but the body content of the page is not rendered. After 3 seconds, the entire page is rendered while waiting for the script in the header tag to load.
Put it at the bottom of the body
<body>
<h2>Script loading mechanism</h2>
<script src='/js/test1.js'></script>
<script src='/js/test2.js'></script>
<script src='/js/test3.js'></script>
</body> Copy the code
This time the HTML content is rendered in the first place and then waiting for js to load.
conclusion
The script blocks rendering of the page, so it is recommended to place it at the bottom of the body, because by the time the script tag is parsed, most of the page will have already been rendered, giving the user a non-blank page immediately.
Also, you can see that multiple scripts make requests to the server asynchronously, they don’t depend on each other, and they end up waiting 3 seconds instead of 3+3+3 seconds.
Does the script delay time affect the execution order?
We usually write scripts in the following order:
<script src="/js/test1.js"></script>
<script src="/js/test2.js"></script>
<script src="/js/test3.js"></script>
Copy the code
Each script outputs a simple logic:
// test1.js
console.log('test1');
Copy the code
If there is no problem with the resource request, the script is usually executed in the expected order and you can look at the console and see the corresponding output:
test1
test2
test3
Copy the code
In order to simulate the complex network environment, assuming that each request has a delay (first request and last response), will their execution order be affected?
function setTime(path) {
if (path == '/js/test1.js') {
return 3 * 000;
} else if (path == '/js/test2.js') {
return 2 * 1000;
} else { return 1 * 1000; } } app.use(async (ctx, next) => { // await lazyLoadScript(ctx.path); await lazyLoadScript(ctx.path, setTime(ctx.path)); await static(path.join(__dirname, 'public'))(ctx, next); }); Copy the code
That’s consistent with what we saw before. Multiple scripts are loaded asynchronously. Although the response time between scripts is different, the final execution order is the same as the request order.
After 3 seconds test1 test2 test3Copy the code
It also verifies that multiple scripts do not block each other, as mentioned above.
Defer and async
These two have to be discussed together because they both have a delay effect.
defer
Initially, we mentioned where the script was placed (header and body), and the defer attribute solved this problem.
<head>
<script defer src="/js/test1.js"></script>
<script defer src="/js/test2.js"></script>
<script defer src="/js/test3.js"></script>
</head>
Copy the code
The script tag that marks defer, even if written in the header location, does not block the loading of the page. But before the document is finished loading.
At the same time, these scripts are executed in the same order as they were written, regardless of delays.
async
Async and defer are similar, but differ in the following two points:
- If the script is loaded first, execute it first
- After document is loaded completely, the async markup script is executed
We’ve seen this before: scripts are not affected by latency and execute in the same order as they are requested.
If we define a global variable in test1.js, the script will fetch the value later when test3.js is run, even if the response is delayed for a long time.
// Delay 3 seconds
console.log('test1');
var globalNum = 1;
Copy the code
// Delay 1 second
console.log('test3');
console.log(globalNum);
Copy the code
However, in a script with the async tag, the order of execution is different:
Test1.js returns the global variable defined by test1.js before it has been declared.
conclusion
The main function of defer and Async is similar in that it does not block rendering of page content.
However, you need to be careful when using async properties. Because it deviates from the agreed order between scripts, it is recommended to use it in scripts unrelated to the business code to avoid script dependencies.
Document. Ready and window. Onload
Document. ready is a jQuery method that listens for the Document DOMContentLoaded event. Here we’ll use document.ready.
Next, test the order of execution between them (script at bottom of body) :
<body>
<script>
window.onload = function () {
console.log('window ready');
}; document.addEventListener('DOMContentLoaded'.function () { console.log('document ready'); }); </script> <script src="/js/test1.js"></script> <script src="/js/test2.js"></script> <script src="/js/test3.js"></script> </body> Copy the code
The script loads and document.ready and window.onload in the following order:
The document DOMContentLoaded event is triggered after the script is fully executed, and window.onload is executed.
What’s the difference between Document. ready and window.onload?
First, window.onload is later than document.ready. In addition, if the page has an asynchronous resource (image), window.onload waits for the image resource to respond before triggering.
You can see that window.onload is called only after the image is loaded.
Differences when using Async
Using defer does not affect the order of execution between them, as the script executes before Document.ready.
Async, on the other hand, makes a big change to the original execution:
<script>
window.onload = function () {
console.log('window ready');
};
document.addEventListener('DOMContentLoaded'.function () { console.log('document ready'); }); </script> <script async src="/js/test1.js"></script> <script async src="/js/test2.js"></script> <script async src="/js/test3.js"></script> Copy the code
Document.ready will no longer wait for the script to load, but will be triggered when the page is rendered. Async scripts are lazily loaded and executed immediately after loading.
Dynamically loading scripts
Straight to the code (from High Performance Javascript) :
<script>
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = '/js/test1.js';
document.getElementsByTagName('head') [0].appendChild(newScript); // The script is loaded if (newScript.readyState) { // IE newScript.onreadystatechange = function () { if (newScript.readyState == 'loaded' || newScript.readyState == 'complete') { console.log('loaded', newScript.src); } }; } else { newScript.onload = function () { console.log('loaded', newScript.src); }; } </script> Copy the code
When the page loads, it simply parses the code inside the Script tag. When the document is all ready, a request is sent to load the resource.
This will not affect the rendering of the page content, and the code above adds dynamically loaded scripts to the head tag, immune to errors within the body.
In fact, it should be found that baidu statistics code, or some scripts from other platforms are dynamically injected into our pages through this form.
The last
I’ve been asked this question before, and my answer was simple.
But through such serious practice, feel to understand the truth of the promotion of web page performance is very helpful. I hope to be of help to you as well. If not, please comment on it. Thank you.
This article is formatted using MDNICE