Saturday, May 23, 2020

Efficiently load JavaScript with defer and async

When loading a script on an HTML page, you need to be careful not to harm the loading performance of the page. Depending on where and how you add your scripts to an HTML page will influence the loading time

Async and Defer

Both async and defer are boolean attributes. Their usage is similar:

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

if you specify both, async takes precedence on modern browsers, while older browsers that support defer but not async will fallback to defer.

Performance comparison

No defer or async, in the head

Here’s how a page loads a script without either defer or async, put in the head portion of the page:

Without defer or async, in the head

The parsing is paused until the script is fetched, and executed. Once this is done, parsing resumes.

No defer or async, in the body

Here’s how a page loads a script without defer or async, put at the end of the body tag, just before it closes:

Without defer or async, in the body end

The parsing is done without any pauses, and when it finishes, the script is fetched, and executed. Parsing is done before the script is even downloaded, so the page appears to the user way before the previous example.

With async, in the head

Here’s how a page loads a script with async, put in the head tag:

With async

The script is fetched asynchronously, and when it’s ready the HTML parsing is paused to execute the script, then it’s resumed.

With defer, in the head

Here’s how a page loads a script with defer, put in the head tag:

With defer

The script is fetched asynchronously, and it’s executed only after the HTML parsing is done.

Parsing finishes just like when we put the script at the end of the body tag, but overall the script execution finishes well before, because the script has been downloaded in parallel with the HTML parsing.

So this is the winning solution in terms of speed 🏆

Blocking parsing

async blocks the parsing of the page while defer does not.

Blocking rendering

Neither async nor defer guarantee anything on blocking rendering. This is up to you and your script (for example, making sure your scripts run after the onLoad) event.

domInteractive

Scripts marked defer are executed right after the domInteractive event, which happens after the HTML is loaded, parsed and the DOM is built.

CSS and images at this point are still to be parsed and loaded.

Once this is done, the browser will emit the domComplete event, and then onLoad.

domInteractive is important because its timing is recognized as a measure of perceived loading speed. See the MDN for more.

Keeping things in order

Another case pro defer: scripts marked async are executed in casual order, when they become available. Scripts marked defer are executed (after parsing completes) in the order which they are defined in the markup.

Just tell me the best way

The best thing to do to speed up your page loading when using scripts is to put them in the head, and add a defer attribute to your script tag:

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

This is the scenario that triggers the faster domInteractive event.

Considering the pros of defer, is seems a better choice over async in a variety of scenarios.

Unless you are fine with delaying the first render of the page, make sure that when the page is parsed the JavaScript you want is already executed.

Monday, May 18, 2020

Call by name vs call by value in Scala, clarification

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

scala> callByValue(something())
calling something
x1=1
x2=1

scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. Instead, call-by-name functions recompute the passed-in expression's value every time it is accessed.


Another Example:

Imagine you want to build a "nagger app" that will Nag you every time since time last you got nagged.

Examine the following implementations:

object main  {

    def main(args: Array[String]) {

        def onTime(time: Long) {
            while(time != time) println("Time to Nag!")
            println("no nags for you!")
        }

        def onRealtime(time: => Long) {
            while(time != time) println("Realtime Nagging executed!")
        }

        onTime(System.nanoTime())
        onRealtime(System.nanoTime())
    }
}

In the above implementation the nagger will work only when passing by name the reason is that, when passing by value it will re-used and therefore the value will not be re-evaluated while when passing by name the value will be re-evaluated every time the variables is accessed


Friday, May 8, 2020

How to use group_concat in hibernate criteria?

You have two options (depending on your hibernate version).

Override the dialect class any hibernate version

You will need to subclass your dialect to add group_concat()

  1. Introduce the dialect override class

Create the following class somewhere in your app (e.g. util package)

package com.myapp.util;

import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes;

public class MySQLCustomDialect extends MySQL5Dialect {
    public MySQLCustomDialect() {
        super();
        registerFunction("group_concat", 
            new StandardSQLFunction("group_concat", 
                StandardBasicTypes.STRING));
    }
}
  1. Map the dialect override class to boot properties

        Add the following property to your application.properities

spring.jpa.properties.hibernate.dialect = com.myapp.util.MySQLCustomDialect


Use JPA Metadata Builder Contributor hibernate 5.2.18 or newer only

  1. Introduce metadata builder class

Create the following class, remember to add package & resolve imports.

public class SqlFunctions implements MetadataBuilderContributor {

@Override
public void contribute(MetadataBuilder metadataBuilder) { 
    metadataBuilder.applySqlFunction( "group_concat", 
        new StandardSQLFunction( "group_concat", 
            StandardBasicTypes.STRING ) ); }
}
  1. Map new class in application boot properties

Leave the dialect properties as is

     spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
     spring.jpa.properties.hibernate.metadata_builder_contributor = com.myapp.util.SqlFunctions

Recent Post

Databricks Delta table merge Example

here's some sample code that demonstrates a merge operation on a Delta table using PySpark:   from pyspark.sql import SparkSession # cre...