Improve page loading speed for high parallel loading of script resources .. we may need to dynamically load scripts... one unavoidable method is to use head. appendchild (SCRIPT); because this method can directly cross-origin.
However, sometimes the dynamic loading of Scripts may ensure their execution sequence. the ideal state is that all scripts can be performed only when the current number of HTTP connections is allowed. while maximizing parallel loading .. you can choose to execute in sequence or in the order of completion of loading.
Suppose we have three JS types: A. js B. js C. js. The traditional method is as follows:
<SCRIPT src = "A. js"> </SCRIPT>
<SCRIPT src = "B. js"> </SCRIPT>
<SCRIPT src = "C. js"> </SCRIPT>
In this way, only the new versions of ff3.0 + and opera can ensure their parallel loading, while other browsers only enable an HTTP connection for them.
There are several ways for them to load in parallel in other browsers, such as using IFRAME, such as document. write, for example, head. appendchild (SCRIPT) such as xhr request and then eval. for example, xhr injection (xhr and head. appendchild (SCRIPT ). where document. write to the script block. some problems may cause some browsers to warn that they are dangerous.Code. And some other problems. for details, go to the yslow blog. the other methods obviously cannot easily solve cross-domain problems. so let's discuss the key head of this article. appendchild (SCRIPT) method.
This method can easily capture scripts in non-ie scenarios. onload and script. onerror, but we can only use script for IE. onreadystatechange to determine the load execution status. onerror must be the same as the request. JS files can be better judged by some conventions. this detail is not covered in this article...
We should clarify before continuing the topic.
Why does a script need to be added dynamically. onload. for example,. js B. js c. if the execution sequence of the three JavaScript scripts is dependent, we must ensure that. js B. js c. JS execution in order... however, if they are loaded concurrently, only Firefox and opera can ensure that they execute these scripts in the order of request initiation. other browsers initiate requests to the server first. only one result is returned, that is, the first load is completed, and the first execution is performed. to make our loader API more robust... I had to sacrifice the parallel loading advantage in other browsers, but instead loaded the next method after the execution was completed... of course, here we have another solution, which will be later mentioned. now we want to simplify the requirement. We only want to call back the method we specified after Script Loading and execution is complete.
The code for non-ie is very simple as follows:
VaR script = Document. createelement ('script ');
Script. onload = function () {alert ('callback ');};
Script. src = "A. js ";
Document. getelementsbytagname ('head') [0]. appendchild (SCRIPT );
It's that simple, right? But unfortunately, ie does not support the script. onload event. At this time, we have to use
Script. onreadystatechange = function () {script. readystate = 'a value '}
This method is used to determine whether the script is loaded and executed.
The value of readystate may be as follows:
- "Uninitialized"-Original Status
- "Loading"-downloading data ..
- "Loaded"-Download complete
- "Interactive"-execution is not completed yet.
- "Complete"-script execution is complete.
Now the problem arises. Some differences between IE6 and IE7 IE8 are roughly divided into the following situations:(In the following status, I have asked a few friends to help test and I should be able to trust it .)
Script. src = "A. js ";
Document. getelementsbytagname ('head') [0]. appendchild (SCRIPT );
If you write SRC first and append, only one of the complete and loaded will appear. it indicates that the script is loaded and executed, but sometimes it cannot be determined whether it is related to the Script Loading time and script execution time.
While
Document. getelementsbytagname ('head') [0]. appendchild (SCRIPT );
Script. src = "A. js ";
Append the SDK first and then compare it with SRC. If you compare it with others, the complete and loaded may appear at the same time. IE7 and IE8 can always ensure that loaded is in the last state. In this case, IE7 8 can trust the script in the loaded state. loading and execution have been completed. however, IE6 is quite depressing because of the different Script Loading time and Script Loading execution time, which leads to the different order of appearance of loaded and complete... at this time, we cannot know which status is the script execution completion status... to determine whether or not the script is executed in this state, we need to use extra switch variables to trust the last status that appears to be the status in which the script is executed.
After a large number of tests, I came to the conclusion that if you want to avoid any trouble, set the src attribute for the script first, and appedchild it to the DOM tree... in this way, we only need this code to determine that the script execution is complete.
If (/loaded | complete/. Test (script. readystate) // IE6 IE7 IE8 General. Well, after solving the readystate problem, let's take a look at another problem.
The solution provided by the great god Nicholas C. zakas is as follows::
View sourceprint?
01 |
If (Script. readystate ){ // IE |
02 |
Script. onreadystatechange = Function (){ |
03 |
A. Push (script. readystate ); |
04 |
If (Script. readystate = "Loaded" | Script. readystate = "Complete" ){ |
05 |
Script. onreadystatechange = Null ; |
06 |
Callback & callback (); |
12 |
Script. onload = Function (){ |
Obviously, two problems are ignored.
1. script. onreadystatechange = function () {} This method may cause irreparable cross page leak memory leakage in some versions of IE6 (for the time being, I am only sure that the SP3 patch IE6 is correct) so even if he hasScript. onreadystatechange = NULL; meaningless for IE6
2. opera also supports readystate. Therefore, this script may cause problems in opera's newer browsers... another IE version supports script. onload, we may not be able to enjoy this benefit.
For 1
We recommend that you use attachevent. Please remember that any non-attachevent event registered in IE6 (except for hard encoding written in HTML) will cause irreparable cross-page memory leakage in IE6. the amount of data in the closure where the callback function is located depends on the data size. the deeper the scope chain, the more things will be affected... the greater the harm.
For 2
I think it is correct to give priority to onload. For example:
View sourceprint?
1 |
Function Isimplementedonload (SCRIPT ){ |
2 |
Script = script | document. createelement ( 'Script' ); |
3 |
If ( 'Onload' In Script) Return True ; |
4 |
Script. setattribute ( 'Onload' , '' ); |
5 |
Return Typeof Script. onload = 'Function' ; // FF true ie false. |
Obviously, as the amount of Code increases, the dynamic loading of script blocks is becoming more and more reliable ....
Let's talk about some problems in the application.
Ideally, all scripts should maximize the number of currently available HTTP connections. I will use the machine to load the script in parallel instead of blocking one by one... but it is obviously not easy to achieve everything.
They should be handled in the next process.
1. The xhr eval or xhr injection methods can be used to conveniently control the execution time series while ensuring parallel resource download.
2. 1. If the cross-origin problem cannot be solved, the script block dynamic loading method should be used. However, we should know that this method is not the first purpose of parallel loading when the FF operabrowser requires execution of the sequence.
3. the solution provided by the friend bottle in the group is to use postmessage IE6 7 to use the window. the opener vulnerability implements Domain Communication and then uses an introduced IFRAME page to request the script and then transmits the script content to the parent page.
Solution 3 bottle given Demo: http://www.webairness.com/apps/libs/local2.html
Well, back to the original topic, please remember that loading scirpt blocks dynamically may still block windows. in the case of onload, of course (hard encoding is always blocked), we can write the request code to setTimeout 1 ms so that we can get an earlier window. the earlier the onload, the advantage of onload is that when we are in the window. onUnload releases some event listening callback functions to avoid memory leaks. because the onload of Some browsers will never happen if it doesn't happen. This is a very helpless problem .... this is why we recommend that you use IFRAME to solve some cross-origin problems... because firame will block the onload ....