Why you should avoid using document.write, specifically for scripts injection

Web performance testing tools such as Google Page Speed or Dareboost have been advising this for a while: injecting a script with document.write has a significant impact on website loading time. Let’s talk about this topic one more time, as the next Chrome update (version 54) won’t allow such scripts injections any longer. What kind of issues may you experience? What are the alternatives?

Chrome won’t execute Scripts injected via document.write any longer

Paul Kinlan announced it on early September on developers.google.com website: Chrome will soon intervene againstdocument.write instruction and, as a consequence, disallow scripts injection via this instruction. Indeed, this change is about to occur from mid-october, with the release of Chrome 54. Some warnings can be noticed yet within the Chrome 53 Developer Console for concerned websites.

What kind of blocking exactly?
Fortunately, for most of websites, blocking cases will be quite limited, only when all the following conditions are met:

  • The user is experiencing very poor network connectivity,
  • The script is parser-blocking (neither async nor defer attributes) and is not already in the browser cache,
  • The instruction is added in the top level document (e.g. iframes won’t be concerned),

If all of those conditions are met, the script will simply not be loaded. So beware if your web pages integrate third-party services. Even if you don’t use that instruction by yourself, your website may present such a dependency, that soon will not work anymore with part of your visitors.

Even if this evolution may cause failures on some websites, Chrome’s strategy is interesting though, aiming to push out (very) bad practices. As detailed below,document.write indeed comes with significant performance issues.

Issues caused by document.write

When you use the following Javascript instruction to inject a script:

document.write('<script src="https://example.com/script.js"></script>');

the web browser has to pause the HTML parsing. The web browser is forced to wait for the resource to load AND to be executed. The situation could even be more harmful, as the browser will also have to wait for additional scripts that could be injected subsequently! Not such a rare situation considering all the third-party services you are probably using on your web pages.  Chrome has published the results of their own tests: 7.6% of the web pages are concerned by this issue, and may face the Chrome intervention regarding document.write usage!

By the way, we can also learn how much thedocument.write instruction can be a performance killer… Let’s have a look at the Chrome’s tests results (1% of their users over a 2G connection): by blocking  document.write usage, the time to parse pages was 38% faster on average, representing a benefit of nearly six seconds!

Another issue to be considered about usingdocument.write (and not only in a script injection case): if the DOM tree has already been built, the use of document.write will force the browser to build it again… A pity for the performance! (document.write writes to the document stream, calling document.write on a closed – loaded – document will reset the current document.)

How to avoid the use of document.write

Generally, you should avoid the use of blocking JavaScript. “Defer” and “async” attributes will let you invoke external scripts asynchronously. However, be careful regarding the execution order of your scripts, as this order is not guaranteed in an asynchronous loading case!

If the use of document.write concerns a third-party service, you have to check if your provider offers an asynchronous loading alternative. If it doesn’t, then consider working with an alternative service.

Finally, in order to insert contents in your web pages, prefer DOM manipulation rather than using document.write. Here is an example of script:

var sNew = document.createElement("script");
sNew.async = true;
sNew.src = "https://example.com/script.min.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(sNew, s0);

Please note that our website speed test and analysis tool penalize the use of document.write, especially when using a mobile context. An easy way for you to make sure you’re complying with the performance best practices!