Details of Javascript loading and execution

  • 2020-03-30 04:18:19
  • OfStack

First, I want to talk about loading and executing Javascript. In general, browsers have two main features for running Javascript: 1) they execute immediately after loading, and 2) they block subsequent content of the page (including rendering of the page, downloading of other resources). Thus, if more than one js file is introduced, the js files are loaded serially and executed sequentially for the browser.

Because javascript might manipulate the DOM tree of an HTML document, browsers generally don't download js files in parallel as they would if they were downloading CSS files in parallel because of the special nature of the js file. So, if your javascript wants to manipulate the following DOM elements, basically the browser will tell you that the object is missing. Because when Javascript executes, the HTML behind it is blocked, and the DOM tree has no DOM nodes behind it. So the program reports an error.

The traditional way

So, when you write the following code in your code:


<script type="text/javascript"
        src="http://coolshell.cn/asyncjs/alert.js"></script>

Basically, in the head < Script> Tags block subsequent resource loads and entire page generation. I made a special example for you to look at: example one. Note: there is only one sentence in my alert. Js: alert(" hello world "), which makes it easier to see how javascript blocks the next thing.

So, you know why a lot of websites put javascript at the end of their pages, either with window.onload or docmuemt ready events.

In addition, because most Javascript code does not need to wait for pages, we have the ability to load asynchronously. So how do we load asynchronously?

Document. The write mode

So, you might think that document.write() would solve the problem of not blocking. Of course you would think document.write is Script> After the tag, you can execute the rest of the stuff. That's right. This is true for Javascript code in the same script tag, but it will still block for the entire page. Here is a sample of the test code:


<script type="text/javascript" language="javascript">
    function loadjs(script_filename) {
        document.write('<' + 'script language="javascript" type="text/javascript"');
        document.write(' src="' + script_filename + '">');
        document.write('<'+'/script'+'>');
        alert("loadjs() exit...");
    }
    var script = 'http://coolshell.cn/asyncjs/alert.js';
    loadjs(script);
    alert("loadjs() finished!");
</script>
<script type="text/javascript" language="javascript">
   alert("another block");
</script>

What do you think the order of alerts is? You can try it in different browsers. Here's the test page you want to close: example 2.

Script's defer and async properties


<script defer type="text/javascript" src="./alert.js" >
</script>

In the case of IE, this tag causes IE to download the js file in parallel and hold its execution until the entire DOM is loaded. Script> It also runs in the order it appears at execution time. The most important is < Script> When deferred is added, it does not block subsequent DOM renders. But because this defer is only for IE, it is generally used sparatively.

And our standard HTML5 also adds an asynchronous loading javascript property: async, whatever value you assign to it, as soon as it appears, it starts loading the js file asynchronously. However, one of the more serious problems with async's asynchronous loading is that it faithfully implements the "execute right after load" catch, so while it doesn't block page rendering, you can't control the order or timing of its execution. You can take a look at this example to get a feel for it.

Create the DOM mode dynamically

This is probably the most used method.


function loadjs(script_filename) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', script_filename);
    script.setAttribute('id', 'coolshell_script_id');
 
    script_id = document.getElementById('coolshell_script_id');
    if(script_id){
        document.getElementsByTagName('head')[0].removeChild(script_id);
    }
    document.getElementsByTagName('head')[0].appendChild(script);
}
 
var script = 'http://coolshell.cn/asyncjs/alert.js';
loadjs(script);

This approach has become almost the standard asynchronous way of loading js files. See example 3 for a demonstration of this approach. This is also played out in JSONP, where I can specify some background script (like PHP) for the SRC of the script, and this PHP returns a javascript function that takes a json string and returns a function that calls our predefined javascript. You can take a look at this example: T.J.S (this example is a small example of an asynchronous ajax call I solicited on twitter earlier)

Load js asynchronously on demand

The DOM example above solves the problem of loading Javascript asynchronously, but not the problem of us wanting it to run at the time we specify. So, we just need to tie the above DOM method to an event.

Such as:

Bind to the window.load event -- example 4

Be sure to compare the execution of example 4 with that of example 3. I used a code highlighted javascript in both examples. Just look at the execution of the highlighted script and the execution of my alert.


window.load = loadjs("http://coolshell.cn/asyncjs/alert.js")

Tied to a specific event -- example 5


<p style="cursor: pointer" onclick="LoadJS()">Click to load alert.js </p>

This is a simple example. When you click on a DOM element, it actually loads our alert. Js.

More and more

However, binding to a particular event seems to be going a bit too far, because only clicking will actually download js, which is slow again. Okay, so this is where we throw our ultimate problem -- we want to asynchronously download the js file to the user's local location, but not execute it, only when we want to execute it.

If only we had the following:


var script = document.createElement("script");
script.noexecute = true;
script.src = "alert.js";
document.body.appendChild(script);
 
//We can do this later
script.execute();

Unfortunately, this is just a beautiful dream, today our Javascript is still relatively primitive, this "JS dream" has not been realized.

So, our programmers have to hack.

Some programmers use the type of a non-standard script to cache javascript. Such as:


<script type=cache/script src="./alert.js"></script>

Because of "cache/script", this thing cannot be parsed by the browser at all, so the browser cannot execute alert. Js as javascript, but it has to download the js file, so it can be done. Unfortunately, webkit is strictly compliant with the HTML standards - for this unknown, just delete, nothing. Then, our dream is broken.

So, we need to hack again, just like we did with preload pictures years ago, we can use the object tag (or the iframe tag), so we have the following code:


function cachejs(script_filename){
    var cache = document.createElement('object');
    cache.data = script_filename;
    cache.id = "coolshell_script_cache_id";
    cache.width = 0;
    cache.height = 0;
    document.body.appendChild(cache);
}

And then, let's call this function at the end. See the related example: example 6

In Chrome, press Ctrl+Shit+I, switch to the network page, you can see that the alert. Js has been downloaded but not executed, and then we will use the example 5 method, because the browser side has cache, will not be downloaded from the server alert. Js. So, you can guarantee the execution speed.

You're probably familiar with this preload thing. You can also use Ajax in the following ways:


var xhr = new XMLHttpRequest();
xhr.open('GET', 'new.js');
xhr.send('');

So I'm not going to say any more here, and I'm not going to give you an example, so you can try it on your own.

Finally, two js are mentioned, one is ControlJS and the other is called HeadJS, which is used to do asynchronous load javascript files.


Related articles: