document.write() Intervention!

The use of document.write() has always been a bad “code smell” in JavaScript. Most web performance guides such as WebPageTest and Yahoo Exception Performance have warned against this practice.

In most cases, document.write() can be replaced by inserting innerHTML into an empty element after the rest of the page loads. This approach also allows the developer to “think” about how the page might react in cases where JavaScript is disabled or not available on the client.

Google has recently changed the default behavior, such that when on a slow (currently 2G) connection, but discussions have also leaned toward including any slow connection.
As such, right now, the following will occur on slow (2G) connections:

  • Chrome 53+ (warning displayed in debugger console)
  • Chrome 55+ (blocked – code will not execute, warning message will appear in debugger console)

For users on slow connections, such as 2G, external scripts dynamically injected via document.write() can delay the display of main page content for tens of seconds, or cause pages to either fail to load or take so long that the user just gives up. Based on instrumentation in Chrome, we’ve learned that pages featuring third-party scripts inserted via document.write() are typically twice as slow to load than other pages on 2G.

My advice – remove all use of document.write() for required content in your code now, as your users MAY NOT see that content if you do not.


Modify Ubuntu Swappiness for performance

Sometimes, it is possible to improve the performance of Ubuntu on older hardware by modifying the disk swapping behavior.

Check your current setting:

cat /proc/sys/vm/swappiness

To modify the behavior, just change the value and reboot. Most documentation recommends trying a value of 10.

sudo vi /etc/sysctl.conf

Add (or change):

# Decrease swappiness value (default:60)


Squid3 Proxy on Ubuntu

Using a personal proxy server can be helpful for a variety of reasons, such as:

  • Performance – network speed and bandwidth
  • Security – filtering and monitoring
  • Debugging – to trace activity

Here are some simple steps to get you started,  obviously you will need to further “harden” security to make it production ready!

sudo apt-get install squid3

cd /etc/squid3/
sudo mv squid.conf squid.orig
sudo vi squid.conf

NOTE: the following configuration works, but will likely need to be adapted for your specific usage.

http_port 3128
auth_param digest program /usr/lib/squid3/digest_file_auth -c /etc/squid3/passwords
#auth_param digest program /usr/lib/squid3/digest_pw_auth -c /etc/squid3/passwords
auth_param digest realm proxy
auth_param basic credentialsttl 4 hours
acl authenticated proxy_auth REQUIRED
acl localnet src # RFC 1918 possible internal network
acl localnet src # RFC 1918 possible internal network
acl localnet src # RFC 1918 possible internal network
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
#acl SSL_ports port 443
#http_access deny to_localhost
#http_access deny CONNECT !SSL_ports
http_access allow localnet
http_access allow localhost
http_access allow authenticated
via on
forwarded_for transparent

Create the users and passwords:

sudo apt-get install apache2-utils (required for htdigest)
sudo htdigest -c /etc/squid3/passwords proxy user1
sudo htdigest /etc/squid3/passwords proxy user2

Open up firewall port (if enabled):

sudo ufw allow 3128

Restart the server and tail the logs:

sudo service squid3 restart
sudo tail -f /var/log/squid3/access.log



MONITORING with Splunk…

sudo /opt/splunkforwarder/bin/splunk add monitor /var/log/squid3/access.log -index main -sourcetype Squid3
sudo /opt/splunkforwarder/bin/splunk add monitor /var/log/squid3/cache.log -index main -sourcetype Squid3


HTML5 Link Prefetching

Link prefetching is used to identify a resource that might be required by the next navigation, and that the user agent SHOULD fetch, such that the user agent can deliver a faster response once the resource is requested in the future.

<link rel="prefetch" href="" />

<link rel="prefetch" href="/images/sprite.png" />

Supported in:

  • MSIE 11+/Edge
  • Firefox 3.5+ (for HTTPS)
  • Chrome
  • Opera


HTML5 preconnect

In addition to dns-prefetch, you can take browser performance one step further by actually creating a new connection to a resource.

By initiating an early connection, which includes the DNS lookup, TCP handshake, and optional TLS negotiation, you allow the user agent to mask the high latency costs of establishing a connection.

Supported in:

  • Firefox 39+ (Firefox 41 for crossorigin)
  • Chrome 46+
  • Opera

<link rel="preconnect" href="//" />
<link rel="preconnect" href="//" crossorigin />


HTML5 DNS prefetch

I often get into some fringe areas of micro-optimizations of website performance, DNS prefetching is another one of those topics.

To understand how this can help, you must first understand the underlying concepts that are used within the communications used to build your web page.

The first of these is a “DNS Lookup”, where the domain name ( is converted into a numerical address, the IP address of the server that contains the file(s).

In many websites, content is included from other domains for performance or security purposes.

When the domain names are known in advance, this approach can save time on the connection as the lookup can fetched in advance, before it is required on the page to retrieve assets.

This can be particularly useful for users with slow connections, such as those on mobile browsers.

<link rel="dns-prefetch" href="//" />

Supported in:

  • MSIE9+ (MSIE10+ as dns-prefetch)/Edge
  • Firefox
  • Chrome
  • Safari
  • Opera


Brotli Compression

If you look at HTTP Headers as often as I do, you’ve likely noticed something different in Firefox 44 and Chrome 49. In addition to the usual ‘gzip’, ‘deflate’ and ‘sdhc’ , a new value ‘br’ has started to appear for HTTPS connections.





Compared to gzip, Brotli claims to have significantly better (26% smaller) compression density woth comparable decompression speed.

The smaller compressed size allows for better space utilization and faster page loads. We hope that this format will be supported by major browsers in the near future, as the smaller compressed size would give additional benefits to mobile users, such as lower data transfer fees and reduced battery use.


  • Brotli outperforms gzip for typical web assets (e.g. css, html, js) by 17–25 %.
  • Brotli -11 density compared to gzip -9:
  • html (multi-language corpus): 25 % savings
  • js (alexa top 10k): 17 % savings
  • minified js (alexa top 10k): 17 % savings
  • css (alexa top 10k): 20 % savings

NOTE: Brotli is not currently supported Apache HTTPd server (as of 2016feb10), but will likely be added in an upcoming release.[email protected]%3E

Until there is native support, you can pre-compress files by following instructions here…


Install Google mod_pagespeed for Apache HTTP

Website network performance is usually a very complicated process. Over the years, I’ve outlined many development techniques that can be used toward this goal. I’d heard about mod_pagespeed for some time, but never had the opportunity to experiment with it until recently. My first impression is that it is a VERY EASY means to gain performance improvements without reworking your existing website to implement techniques for establishing far-future expires, cache-busting, minification and static file merging.

Out of the box, most common techniques are automatically applied to your assets and a local server cache is created to utilize them.

Default installation is trivial:

  1. Download the latest version for your server architecture:




  2. sudo dpkg -i mod-pagespeed-*.deb

  3. sudo apt-get -f install
    (if required)

  4. sudo service apache2 restart

NOTE: Using tools like Firebug will enable you to see an HTTP Header indicating the version being used for your requests.

If you need to modify configuration from the default:

sudo vi /etc/apache2/mods-available/pagespeed.conf

For VirtualDomains, you can selectively enable and disable PageSpeed and many of it’s settings in your appropriate configuration files with:

<IfModule pagespeed_module>
ModPagespeed on

NOTE: Appending ?ModPagespeed=off to your URL will disable functions for that request.


HTML4 script defer

This HTML4 attribute was intended to defer/delay execution of specific javascript code until after the page is rendered. In theory, this makes the website “appear” faster as the functions relevant to the User-Interface can be executed before other “background” processes that would otherwise block the screen from displaying.

<script defer="defer" src="example.js"></script>

NOTE: Do not use defer for external scripts that might depend on each other if you need to support MSIE9 and earlier.


Load Testing web application with Selenium and TestNG

I’ve used Selenium for while to do verification tests of web applications, recently I discovered a very simple way to use it with TestNG and Maven to do some performance testing. TestNG allows for the use of annotations to allow multi-threading and iterations.



And as for a simple test to get started with… scripting of steps is available online or could be in a future blog post.

package com.example.selenium;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
* Simple test example for Selenium
public class SeleniumTest {

private static final Logger LOGGER = LoggerFactory.getLogger(SeleniumTest.class);
* TODO Un-comment or change if needed to set your local path!
public void oneTimeSetUp() {
System.out.println("-------------------------------------- init ----------------------------------------");
* NOTE: uses TestNG - behaves differently than JUnit
@Test(invocationCount = 1, threadPoolSize = 5)
public void testLoadApp() {

final String fn = "testLoadApp";
final String baseUrl = "";
LOGGER.debug("[START] Thread Id: {} is started!", Thread.currentThread().getId());

WebDriver driver = null;
final long start = System.currentTimeMillis();
driver = (WebDriver)new FirefoxDriver();

final String actual = driver.getTitle();
LOGGER.debug("Page Title is {}", actual);
final String expected = "GIANTGEEK.COM";
//perform whatever actions, like login, submit form or navigation

}catch(final WebDriverException ex){
}catch(final Exception ex){
finally {
final long elapsed = System.currentTimeMillis() - start;
LOGGER.debug("[END] Thread Id: {}, elapsed={}", Thread.currentThread().getId(),elapsed);
if(driver != null){

WARNING: Selenium Tests MAY fail if the browser used for testing is updated in the Operating System. Updating the pom.xml to a newer release usually helps!