Get rid of the document.write in your code ("<script ...

Source: Internet
Author: User

In a traditional browser, a synchronized script tag blocks an HTML parser, whether inline or outside, such as:

<Scriptsrc= "A.js"></Script><Scriptsrc= "B.js"></Script><Scriptsrc= "C.js"></Script><imgsrc= "A.jpg">

In this example, the HTML parser will first parse to the first script tag, and then pause parsing, to download a.js, after downloading the execution, after execution, will continue to parse, download, execute the following two script tags, finally parse the img tag, download pictures, show pictures. Assuming that the download time for each file is 1 seconds and that the browser execution time is ignored, you will eventually see A.jpg rendered on the browser at the end of the 4th second.

Today's browser is no longer so linear execution, after encountering the first script tag, the parser in the main thread pauses parsing, but the browser will open a new thread to pre-parse the following HTML source, while Preloading encountered CSS, JS, pictures and other resource files, that is, In modern browsers, the four resource files in this example are downloaded in parallel, so it takes only 1 seconds to render the last image regardless of the time-consuming execution of the browser.

Extra tip:

But the only thing the browser can do is pre-parsing and preloading, the execution of scripts and the construction of the DOM tree must still be linear, so that the rendering of the page must be linear. Scripts must be executed sequentially this is a good understanding, such as b.js is likely to use the variables in the a.js, the DOM tree can not be built in advance of the reasons can also be thought, a.js is likely to query the DOM tree, at that time to execute Queryselectorall ("script"). Length must be 1 , the IMG Word must be 0.

But there is also a thing that can explain the above two optimizations can not do, and even let the pre-parsing and pre-loading the two already done optimization failure, that is document.write (), document.write can be executed in the current script tag after inserting arbitrary HTML source, if you insert a "<div>foo</div>" that's OK, but if you insert an unclosed open tag, for example:

<Script>document.write ("<textarea>") //It can also be document.write ("<!--"), etc.</Script><Scriptsrc= "A.js"></Script><Scriptsrc= "B.js"></Script><Scriptsrc= "C.js"></Script><imgsrc= "A.jpg">

When the 1th script tag is completed, the browser will find that because the document.write output an unclosed open tag, so the pre-parse results just done are all thrown away, re-parsed, the second parse after the script tag and the IMG tag became textarea Content, so the pre-loaded JS and image resources are white loaded. But this situation is a minority, pre-analytic benefits far outweigh the disadvantages, so the browser did this optimization, an article on the MDN lists some of the pre-analytic optimizations that will let the browser do the failure of the code.

The main character of this article is to use document.write to output a script tag, such as:

<Scriptsrc= "A.js"></Script><Script>document.write ('<script src= "Http://thirdparty.com/b.js" ><\/script>')</Script><Scriptsrc= "C.js"></Script>

In this example, because the b.js is inserted through the JS code, the HTML pre-parser is not visible, so only when the a.js downloaded and executed, and the second inline script completed, B.js will start to download, that is, b.js can not and a.js and c.js parallel downloaded, resulting in a slow page display, the same assumption that each file download time is 1 seconds, then the three files downloaded after the execution of two seconds, because the b.js can not preload. Execute document.write ("<script ...) in an external chain of JS files such as A.js. is a similar effect.

Chrome engineers have recently found that the page load slowed by the script tag contained in document.write () is common, and there is a general rule that the URLs of these scripts are not (cross-site). Generally are some advertising and statistical functions of the third-party script, is the normal display of the page is not necessary, if it is the site, it is more likely that the current page to show the necessary script.

The engineers also sampled statistics for the 2G environment in Chrome for Android, and found that 7.6% of the pages contained at least one of these script tags, and found that the page itself would show a significant increase in speed if the non-essential scripts were banned from loading:

Using the document.write to load the script, in most cases, is the wrong approach and should be optimized. So how do you optimize it? Do you want to put the normal script tag inside the HTML? No, no, first of all, why not? In general, a script to be placed in the JS to load, rather than directly in the HTML, the possible reasons are:

1. The URL of the script can not be written dead, such as to dynamically add some parameters, the resolution of the user device Ah, the current page URL Ah, prevent the timestamp of the cache ah, and so on, these parameters can only be used to get the first JS, such as the domestic common CNZZ statistical code:

<Script>varCnzz_protocol= (("https:" ==document.location.protocol)? "https://" : "/ http");d Ocument.write (unescape ("%3cspan id= ' cnzz_stat_icon_30086426 '%3e%3c/span%3e%3cscript src= '" +Cnzz_protocol+                         "w.cnzz.com/c.php%3fid%3d30086426 ' type= ' text/javascript '%3e%3c/script%3e"))</Script>

It provides the user with the JS code, rather than the HTML code, is to first use JS to determine the HTTP or HTTPS protocol.

2. The script in the outer chain to upload another script, this situation can not be written in the page HTML, such as the Baidu Alliance in this script may use document.write to load another script:

Http://cpro.baidustatic.com/cpro/ui/c.js

Again, why not, even if there are really a few of the code can be optimized to HTML code, such as the above CNZZ can be changed to:

<id= ' cnzz_stat_icon_30086426 '></span> <  srctype= ' text/javascript '></Script  >

This allows the browser to pre-load, is optimized, but this is not the best optimization, because, when you can obviously feel that your page because of third-party script causes slow, usually not because it is not preloaded, but because it is loaded faster than your own site script loading speed too much, Take this example again:

<Scriptsrc= "A.js"></Script><Script>document.write ('<script src= "Http://thirdparty.com/b.js" ><\/script>')</Script><Scriptsrc= "C.js"></Script>

thirdparty.com site problems, a.js and c.js 1 seconds to load up, and b.js may take 10 seconds to load, that c.js the execution and the subsequent HTML rendering will need to wait 10 seconds, the extreme situation is b.js stuck there until Timeout, if these scripts are placed in the head, the user will never see your page, in the domestic people should have been deep experience, is those who quoted Google statistics, ads and other synchronous version of the script page, in this case, only by pre-loading can not solve the fundamental problem.

The best thing to do is to change it to asynchronous execution, and the async script does not block the HTML parser at all, and it doesn't have to be pre-parsed. The script that is loaded with HTML can be asynchronous by using the Async attribute:

<id= ' cnzz_stat_icon_30086426 '></span> <  async srctype= ' text/javascript '></  Script>

Of course, the outer chain of the script itself may also need to make corresponding adjustments, such as in case there is a document.write, the entire page will be overwritten.

As mentioned above, most third-party scripts need to add dynamic parameters that cannot be modified into HTML code, so it is more common to use document.createelement ("script") to match Appendchild/insertbefore Insert script, and the script inserted in this way is asynchronous, for example:

 <  span  id  = ' cnzz_stat_icon_30086426 '  ></ span  >  <  script  >  document.head.appendchild (Document.createelement ('  script "  =  ' //w.cnzz.com/c.php?id=30086426 '  </ script  >  

At present, most of the domestic and foreign advertising, statistical service providers have to provide asynchronous version of the code, but there may be no, such as CNZZ statistical Code, see here and here.

In the user experience-oriented principle, Chrome's engineers are prepared to make a bold attempt to block out the script, the specific masking rule is that the script corresponding to all of these conditions will not be executed by Chrome:

1. is written with document.write

Unable to pre-parse and pre-load

2. synchronously loaded, i.e. without the ASYC or defer attribute

Even if written in document.write, the async script tag does not block the execution of subsequent scripts and the parsing of the HTML source code behind it.

3. Outside the chain

Inline anyway no network request, does not affect the speed of presentation, and who will write <script>document.write ("<script>alert (' foo ') <\/script>") </ Script> code like this:

4. Cross-site

As mentioned above, the cross-site script affects the content of the page itself is less likely to show, cross-site and cross-domain differences, please see my article

5. This loading of the page is not triggered by a refresh operation

Although it is not possible to say that third-party scripts affect the content and functionality of the main page, there is still this possibility, if the main content of the page is affected, the user will inevitably point to refresh, so when the refresh, the shielding logic to turn off

6. The page is the top level (self = = top), not an IFRAME

Because the IFRAME is often a small chunk of advertising, and the user wants to see the main page is usually the parent page of these IFrame, and the script inside the IFRAME does not block the parent page rendering, so there is no need to optimize them

7. Not being cached

If the outer chain script is already cached, you can certainly execute it directly.

But this is a breaking change, considering the user experience, but also not to consider the site itself, so the changes will step step (I summed up in 4 steps) to execute, to allow developers to modify their own code time, the specific plan is:

1. Warning

Starting with Chrome 53, which is the current stable version, the following warning appears in the console of the developer tools (even if the script has been cached or the page is opened by a refresh operation):

2. Turn on the shield under the 2G network (issue 640844)

Starting with Chrome 54 (released in mid-October 2016), turn on masking in a 2G network environment. It should be noted that blocking a script does not really make a request, but instead sends an asynchronous request with a low priority (priority is 0,chrome for each HTTP request). The purpose of this asynchronous request is not to execute it (it also says that a synchronization script executes directly as an asynchronous script, which is likely to be problematic), but rather to:

(1) In order to put the script in the cache, that is, the first block, the second page and other operations if you need to the script, it is likely already in the cache, which is to reduce the probability of breaking.

(2) in order to notify the server where the script is located, "Your script was blocked by me". When the script is blocked, the asynchronous request is added by Chrome to a special request header intervention, which is a corresponding Chromestatus URL:

Intervention: 

If you are a third-party service provider, such as the head of the ad delivery system, you see this request header in your server's access log, it means your script has been blocked, and you can see from Referer that the blocked script is referenced on which page. Then all you need to do is let this website update the code you provide to an asynchronous version.

Because it is 2G, it must be the mobile version of Chrome, which is chrome for android,android WebView do not know that will not open, in June, the official release of Chrome said that it has not been decided to open in WebView:

Would this feature is supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?

This feature'll be enabled on Win, Mac, Linux, ChromeOS and Android, but we're still deciding whether it's Appropri Ate to apply the intervention for WebView.

The Chrome for IOS kernel is not blink and unaffected.

To facilitate debugging, switching the network to 2g in the Chrome PC Developer tool also triggers this masking rule (still in implementation).

I saw one of my own. Mobile sites that could be affected by then: https://sina.cn/

3. Turn on the shield (issue 640846) in a low-speed 3G and WiFi environment

There is no decision to start from which version, if the previous 2G phase is smooth, it is possible to enter this phase, and so on when there is a message I will append the specific open version number, PC page at this stage will be affected.

I saw two of them. Websites that may be affected at the time: https://www.baidu.com/https://www.taobao.com/

4. Fully shielded

Any network environment is turned on, this is my guess, and I haven't seen anyone in Chrome talking, but even if I do this at the end, it's going to take a long time.

Some students may ask: "I put it at the bottom of the page, it should be all right." Don't forget that the sync script will block the Domcontentloaded/load event, and turn off the VPN to run the following demo try:

<Script>Document.addeventlistener ("domcontentloaded", function() {alert ("perform operations such as asynchronous rendering, binding events, and so on")}) document.write ("<script src=http://www.twitter.com><\/script>")</Script>

With JQuery, all the callback functions in the $ (function () {}) will be jammed, and the problem remains serious.

Finally summed up: "Why say document.write (" <script ...) Bad "-" because it could have been written asynchronously, but it was written in a synchronous and not preloaded "

Ps:chrome is still doing another optimization attempt, which is to open a separate V8 thread to execute those containing the document.write ("<script ...) The code in the inline script tag of the typeface then preloaded that script, but as I said above (Preloading does not solve blocking problems), even if this optimization is really done, it doesn't make much sense.

The pps:html specification also makes corresponding modifications, saying that the browser is allowed to do this optimization.

Get rid of the document.write in your code ("<script ...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.