Page life cycle

DOMContentLoaded

  • DOMContentLoaded — The browser has fully loaded the HTML and built the DOM tree, but external resources like and stylesheets may not have finished loading.

    • Occurs on a Document object and must be captured using addEventListener:

      document.addEventListener("DOMContentLoaded", ready);
      Copy the code
    • You can apply JavaScript to elements, such as finding DOM nodes.

    • Such as < script >… Scripts like block DOMContentLoaded and the browser waits for them to finish executing.

    <script>
      document.addEventListener("DOMContentLoaded".() = > {
        alert("DOM ready!");
      });
    </script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"></script>
    
    <script>
      alert("Library loaded, inline script executed");
    </script>
    
    // Library loaded... "Before you see" DOM Ready! (All scripts have been executed)
    Copy the code

    Does not block DOMContentLoaded scripts

    There are two exceptions to this rule:

    1. withasyncAttribute scriptDoes not blockDOMContentLoaded.
    2. usedocument.createElement('script') A script that is dynamically generated and added to a web pageIt doesn’t blockDOMContentLoaded.
    • External stylesheets do not affect the DOM, so DOMContentLoaded does not wait for them. But if you have a script behind the style, that script must wait for the stylesheet to load. While DOMContentLoaded waits for the script, it is now also waiting for the style in front of the script:
    <link type="text/css" rel="stylesheet" href="style.css">
    <script>
      // The script will not be executed until the stylesheet is loaded
      alert(getComputedStyle(document.body).marginTop);
    </script>
    Copy the code
    • Firefox, Chrome, and Opera all auto-populate forms in DOMContentLoaded.

load

  • Load – The browser loads not only the HTML, but all external resources: images, styles, etc.

    <script>
      window.onload = function() { // Same as this window.addEventListener('load', (event) => {
        alert('Page loaded');
    
        // The image has been loaded
        alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
      };
    </script>
    
    <img id="img" src="https://en.js.cx/clipart/train.gif? speed=1&cache=0">
    Copy the code
  • Beforeunload event — The user is leaving: We can check if the user has saved changes and ask if he really wants to leave.

    You can try this by running the following code and then reloading the page:

    window.onbeforeunload = function() {
      return false;
    };
    Copy the code

    For historical reasons, returning a non-empty string is also considered a cancellation event. Browsers used to display them as messages, but according to modern specifications, they shouldn’t.

    window.onbeforeunload = function() {
      return "There are unsaved changes. Leave now?";
    };
    Copy the code

    Its behavior has changed as some webmasters have abused the event handler by displaying misleading and malicious messages. So, for now, some older browsers may still display it as a message, but otherwise — you can’t customize the message that is displayed to the user.

unload

  • Unload Events – The user has almost left, but we can still start some operations (only simple operations that don’t involve delay or questioning the user), such as sending statistics.

    • We can usenavigator.sendBeaconTo send network requests. See the specificationw3c.github.io/beacon/. It will beSend data in the backgroundThere is no delay in switching to another page: the browser leaves the page, but it is still executingsendBeacon.
    let analyticsData = { /* An object with collected data */ };
    
    window.addEventListener("unload".function() {
      navigator.sendBeacon("/analytics".JSON.stringify(analyticsData));
    });
    Copy the code
    • Requests are sent in POST mode.
    • We can send not only strings, but forms and other forms of data, but usually it’s a string-like object.
    • The data size is limited to 64kb.

    By the time the sendBeacon request completes, the browser may have left the document, so the server response cannot be retrieved (usually empty for parsing data).

document.readyState

  • The document.readyState property gives us the loading status of the current document.

    • Loading — The document is being loaded.

    • Interactive — The document is read in full.

      • withDOMContentLoadedAlmost at the same time, butinDOMContentLoadedbeforeTo happen.
    • Complete — The document is fully read and all resources (such as images, etc.) have been loaded.

      • withwindow.onloadAlmost at the same time, butinwindow.onloadbeforeTo happen.
    • You can track state changes in the readyStatechange event.

    // Print it when the state changes
    document.addEventListener('readystatechange'.() = > console.log(document.readyState));
    Copy the code

Let’s look at the full event flow.

<script>
  log('initial readyState:' + document.readyState);

  document.addEventListener('readystatechange'.() = > log('readyState:' + document.readyState));
  document.addEventListener('DOMContentLoaded'.() = > log('DOMContentLoaded'));

  window.onload = () = > log('window onload');
</script>

<iframe src="iframe.html" onload="log('iframe onload')"></iframe>

<img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/451f6107a29f49f29dac999cea336d1b~tplv-k3u1fbpfcp-zoom-1.image" id="img">
<script>
  img.onload = () = > log('img onload');
</script>
Copy the code

Typical output:

  1. [1] initial readyState:loading
  2. [2] readyState:interactive
  3. [2] DOMContentLoaded
  4. [3] iframe onload
  5. [4] img onload
  6. [4] readyState:complete
  7. [4] window onload

The numbers in square brackets indicate the approximate time that this happened. Events marked with the same number occur almost simultaneously (± milliseconds).

2,<script>The element

<script>Attributes of an element

The

  • SRC: Optional. Represents an external file that contains the code to execute.

    • If the SRC feature is set, the internal code of the script tag is ignored.
  • Language: Abandoned. Originally used to represent a scripting language (such as “JavaScript”, “JavaScript 1.2”, or “VBScript”) in a code block. Most browsers ignore this property and should never use it again.

  • Charset: Optional. The code character set specified with the SRC attribute. This property is rarely used because most browsers don’t care about its value.

  • Type: Optional. Instead of language, represents the content type (also known as MIME type) of the scripting language in the code block. By convention, this value is always “text/javascript”.

    • If the value is type = “module”, the code is treated as an ES6 module, and only then can the import and export keywords appear in the code.

async

  • Async: Optional. Indicates that the script is downloaded “in the background” and executed when it is ready to load (load priority).

    • This applies only to external script files.

    • Async scripts do not wait for other scripts (there is no guarantee that they will be executed in the order they appear).

    • Asynchronous scripts are guaranteed to be on the pageloadThe event is executed before, but may be executed beforeDOMContentLoadedBefore or after.

    <head> 
        <! The second script may be executed before the first. 
        <script async src="example1.js"></script> 
        <script async src="example2.js"></script> 
    </head> 
    Copy the code

defer

  • defer: optional. saidThe script is downloaded “in the background” and then executed after the DOM is built.
    • This applies only to external script files.

    • There are multiple defers on a page, executed in the order they appear.

    • Executed before the DOMContentLoaded event.

      • In practice, delayed scripts may not always be executed in order or inDOMContentLoadedEvents are executed before (for example, scripts contain timers), so it is best to include only one such script.
    <head> 
        <! -- Execute the second script after the first script 
        <script defer src="example1.js"></script> 
        <script defer src="example2.js"></script> 
    </head> 
    Copy the code

crossoriginAcross the source

  • crossorigin: optional.Configure CORS for related requests (Cross-source resource sharing)Settings. CORS is not used by default.
    • One source (domain/port/protocol) cannot retrieve the content of another source.

    • To allow cross-source access, the

      • None Crossorigin: Access is prohibited.

      • Crossorigin =”anonymous” profile requests do not have to set credentials flags (cookies are not sent, a server-side header is required).

        • If the server responds with a header access-Control-allow-Origin containing * or our source (Origin), Access is allowed.

        • The browser does not send authorization information and cookies to a remote server.

      • Crossorigin =”use-credentials” sets the credential flag, which means that outbound requests contain credentials (cookies are sent, requiring two server-side headers).

        • Access is allowed if the server sends back header Access-Control-allow-Origin and access-Control-allow-credentials: true with our source.

        • The browser sends authorization information and cookies to the remote server.

    <script>
    window.onerror = function(message, url, line, col, errorObj) {
      alert(`${message}\n${url}.${line}:${col}`);
    };
    </script>
    <script crossorigin="anonymous"  src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
    
    <! -- If the server provides the 'access-Control-allow-origin' header, it can be accessed normally. -->
    Copy the code

integrity

  • integrity: optional. allowCompares the received resource with the specified encrypted signatureTo verify Subresource Integrity (SRI).
    • If the signature of the received resource does not match the signature specified by this property, an error is reported and the script is not executed.
    • This property can be used to ensure that a Content Delivery Network (CDN) does not serve malicious Content.

Default execution order

On modern web sites, scripts tend to be “heavier” than HTML: they tend to be larger in size and take longer to process.

tag, and the browser cannot continue to build the DOM. It must execute the script immediately. For external scripts Is the same: the browser must wait for the script to download and execute before proceeding with the rest of the page.

This leads to two important questions:

  1. Scripts do not have access to the DOM elements below them, so they cannot add handlers to them, etc.
  2. If you have a clunky script at the top of the page, it “clogs the page.” The user cannot see inside the page until the script is downloaded and executed, resulting in a significant delay in page rendering, during which the browser window is completely blank.

To solve this problem, modern Web applications typically place all JavaScript references at the end of the element, as shown in the following example:

<! DOCTYPEhtml> 
<html> 
    <head> 
        <title>Example HTML Page</title> 
    </head> 
    <body> 
        <! -- Here is the page content --> 
        <script src="example1.js"></script> 
        <script src="example2.js"></script> 
    </body> 
</html> 
Copy the code

This way, the page renders the page completely before processing the JavaScript code. The user will feel that the page loads faster because the browser displays a blank page for less time.

But the solution is far from perfect. For example, the browser won’t notice the script (and can start downloading it) until the full HTML document is downloaded. For long HTML documents, this can cause significant delays.

That’s nothing for people with high-speed connections, who won’t feel the delay. But there are still many parts of the world where people have slow Internet speeds and far from perfect mobile Internet connections.

Fortunately, defer and Async can solve this problem for us.

Dynamically loading scripts

You can also load a specified script by dynamically adding a script element to the DOM. Just create a script element and add it to the DOM.

let script = document.createElement('script'); 
script.src = 'gibberish.js'; 
document.head.appendChild(script); 
Copy the code

Of course, the request will not be sent until the HTMLElement element is added to the DOM and this code is executed. By default,

You can set script.async = false and the scripts will be executed in the order they were in the document, just as you deferred:

let script = document.createElement('script'); 
script.src = 'gibberish.js'; 
script.async = false; 
document.head.appendChild(script);
Copy the code

Resources obtained in this way are not visible to the browser preloader. This can seriously affect their priority in the resource acquisition queue.

To let the preloader know of the existence of these dynamic request files, declare them explicitly in the document header:<link rel="preload" href="gibberish.js">

Inline code and external files

Although it is possible to embed JavaScript code directly in HTML files, it is generally considered a best practice to place JavaScript code in external files whenever possible. However, this best practice is not explicitly mandatory. External files are recommended for the following reasons.

  • Maintainability. JavaScript code spread over many HTML pages can cause maintenance difficulties. It’s much easier to maintain all your JavaScript files in one directory.

  • The cache. The browser caches all externally linked JavaScript files based on specific Settings (downloads), and then other pages that want the same script are fetched from the cache. This means that if both pages use the same file, it only needs to be downloaded once. This ultimately means pages load faster.

  • Adapt to the future. By putting JavaScript in an external file, you don’t have to worry about the fact that inline code block to solve the problem.

3,<noscript>The element

<noscript>Element to provide alternative content for browsers that do not support JavaScript.

<noscript>Elements can contain anything that can appear in<body>The HTML element in,<script>With the exception of.

The browser will display content contained in

  • Browsers do not support scripting;
  • Browser support for scripts is turned off.

If any of these conditions are met, the content contained in

<! DOCTYPE html><html> 
    <head> 
        <title>Example HTML Page</title> 
        <script defer="defer" src="example1.js"></script> 
        <script defer="defer" src="example2.js"></script> 
    </head> 
    
    <body> 
        <noscript> 
            <p>This page requires a JavaScript-enabled browser.</p> 
        </noscript> 
    </body> 
</html> 
Copy the code

This example is to make the browser display a message when the script is not available. If the browser supports scripting, the user will never see it.

4. Resource loading

Browsers allow us to track the loading of external resources — scripts, iframes, images, etc.

There are two events:

  • Onload – Triggered when the script is loaded and executed.

    • inonloadWe can use variables in scripts, run functions and so on
    let script = document.createElement('script');
    
    // You can load any script from any domain
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
    document.head.append(script);
    
    script.onload = function() {
      // The script creates a variable "_"
      alert( _.VERSION ); // Displays the version of the library
    }; 
    Copy the code
  • Onerror — Error occurs.

    • Unable to obtain more details about HTTP error.
    let script = document.createElement('script');
    script.src = "https://example.com/404.js"; // There is no such script
    document.head.append(script);
    
    script.onerror = function() {
      alert("Error loading " + this.src); // Error loading https://example.com/404.js
    }; 
    Copy the code

The onLoad/onError event only tracks the load itself.

Errors that can occur during script processing and execution are beyond the scope of these event traces. That is: if the script loads successfully, the onload event will be emitted even if there is a programming error in the script.

If you want to track the script error, you can use the window.onerror global handler.

The Load and error events also apply to other resources, and basically apply to any resource that has an external SRC.

let img = document.createElement('img');
img.src = "https://js.cx/clipart/train.gif"; / / (*)

img.onload = function() {
  alert(`Image loaded, size ${img.width}x${img.height}`);
};

img.onerror = function() {
  alert("Error occurred while loading image");
};
Copy the code

But there are a few caveats:

  • Most resources start loading as soon as they are added to the document. But does not start loading until SRC is obtained.
  • The iframe. Onload event is emitted when the

This is for historical reasons.