case
ADM Blog
7Feb/130

Asynchronous and deferred JavaScript execution explained

async and defer are two attributes that a <script> tag can have (and are available in most modern browsers) and are quite useful. Usually you can specify when the JavaScript code should start executing by where you place the tags. Having all the script tags in your <head> will delay your page rendering quite a bit depending on the size of the files and execution time.

Normal <script>

...is the default behavior of the <script> element and whenever the parser encounters a script tag, parsing the HTML code will be paused until the code is loaded and executed. For a page with multiple scripts this may mean a lot

Defered <script defer>

...means the file will load in parallel with the HTML parsing and its execution will be delayed for when the page is fully rendered, thus, the DOM will be available when the scripts starts running

Asynchronous <script async>

...means the file will load whenever, and the script will execute as soon as it's ready. The HTML parsing will pause if the scripts needs to run. Also, you can't rely on the order in which the scripts are executed using async

 

For a more visual description

execution2

11May/100

Check if user visited certain websites

Today I found a website called http://www.stayinvisible.com/ that uses a really clever technique to peak in your browser history. They can't see everything of course but they can see whatever they are interested in and that is a list of web-proxy websites.

So how are they doing it ?

First, they have a list of websites they are interested in, like i said, a list of web-proxies.

1
2
3
4
5
6
7
var sites = {
    "hidemyass.com": ["http://www.hidemyass.com", "http://forum.hidemyass.com"],
    "freeproxy.ca": ["http://www.freeproxy.ca"],
    "proxy4free.com": ["http://www.proxy4free.com"],
    ....
    ....
    }

Second, they create a temporary IFRAME where they write a simple 2 lines CSS that does the magic

1
2
a { color: #000; display: none}
a: visited { color: #F00; display: inline }

... and in the body they append all the links from the sites list.

The browser renders the links, and all the sites that appear in your history will use the "a:visited" CSS class. The others use the normal "a" class that has a display:none property and will be hidden.

What's left to do is iterate all the links from the frame and check if they are visible or not to know which of them are in your history and which of them aren't. Pretty simple eh ?

So here's the class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
var bHistory = function(){
  var sites = {
    "hidemyass.com": ["http://www.hidemyass.com", "http://forum.hidemyass.com"],
    "freeproxy.ca": ["http://www.freeproxy.ca"],
    "proxy.org": ["http://www.proxy.org", "http://www.proxy.org/cgi_proxies.shtml", "http://www.proxy.org/forum/index.html"]
  };
  var visited = {};
  function getStyle(el, scopeDoc,styleProp) {
    if (el.currentStyle) var y = el.currentStyle[styleProp];
    else if (window.getComputedStyle) var y = scopeDoc.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
    return y;
  }
  function remove( el ) {
    el.parentNode.removeChild( el );
  }
  function createIframe() {
    var iframe = document.createElement("iframe");
    iframe.style.position = "absolute";
    iframe.style.visibility = "hidden";
    document.body.appendChild(iframe);
    if(iframe.contentDocument) iframe.doc = iframe.contentDocument;
    else if(iframe.contentWindow) iframe.doc = iframe.contentWindow.document;
    iframe.doc.open();
  	iframe.doc.write('<style>');
  	iframe.doc.write("a{color: #000000; display:none;}");
  	iframe.doc.write("a:visited {color: #FF0000; display:inline;}");
  	iframe.doc.write('</style>');
    iframe.doc.close();
    return iframe;
  }
  var iframe = createIframe();
  function embedLinkInIframe( href, text ) {
    var a = iframe.doc.createElement("a");
    a.href = href;
    a.innerHTML = site;
    iframe.doc.body.appendChild( a );
  }
  for( var site in sites ) {
    var urls = sites[site];
    for( var i=0; i<urls .length; i++ ) {
      embedLinkInIframe( urls[i], site );
      if( urls[i].match(/www\./) ){
        var sansWWW = urls[i].replace(/www\./, "");
        embedLinkInIframe( sansWWW, site );
      } else {
        var httpLen = urls[i].indexOf("//") + 2;
        var withWWW = urls[i].substring(0, httpLen ) + "www." + urls[i].substring( httpLen );
        embedLinkInIframe( withWWW, site );
      }
    }
  }
  var links = iframe.doc.body.childNodes;
  for( var i=0; i<links.length; i++) {
    var displayValue = getStyle(links[i], iframe.doc, "display");
    var didVisit = displayValue != "none";
    if( didVisit ){
      visited[ links[i].innerHTML ] = true;
    }
  }
  remove( iframe );
  var usedSites = [];
  for( var site in visited ){
    usedSites.push( site );
  }
  return usedSites;
}

To use it:

1
2
   var visited = new bHistory();
   alert(visited); // an array with visited websites from the defined list

All credits go to the smart man who did this. Cheers!

26Feb/090

Cross browser inline-block

Ah, inline-block, that elusive and oh so tempting display declaration that promises so much, yet delivers so little. Too many times have I received PSD files like this:

design

and begin to cry.

Normally, this type of layout would be a cakewalk. Fixed width, fixed height, float:left and you’re done. Buuuuut, the design needs to work with variable amounts of content, which means if one of these blocks has more content than the others, it will break the layout:

design

Because the first gallery item is taller than the rest, the 5th item is floated left against it instead of below it. Basically we want a layout with the flexibility of a table, but proper, semantic markup.

We start with a simple page with an unordered list and display set to inline-block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<ul>
    <li>
        <h4>This is awesome</h4>
        <img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
        alt="lobster" width="75" height="75"/>
    </li>
...
</ul><ul>
 
<style>
    li {
        width: 200px;
        min-height: 250px;
        border: 1px solid #000;
        display: inline-block;
        margin: 5px;
    }
</style>
</ul>

And it looks ok in Firefox 3, Safari 3 and Opera:

design

Obviously, something is wrong with the vertical alignment. Well, not exactly wrong, because this is the correct behavior, but it’s not what we want.

What’s going on here is the baseline of each

  • is being aligned with the baseline of the parent < ul>. What’s a baseline, you ask? A picture is worth a thousand words:

    design

    The baseline is the black line running through the text above. Putting it as simply as possible, the default vertical-align value on inline or inline-block element is baseline, which means the element’s baseline will be aligned with its parent’s baseline. Here’s the first inline-block attempt with baselines shown:

    design

    As you can see, each baseline is aligned with the baseline for the text ‘This is the baseline’. That text is not in a < /li>< li>, but simply a text node of the parent < ul>, to illustrate where the parent’s baseline is.

    Anyway, the fix for this is simple: vertical-align:top, which results in a great looking grid:

    design

    Except it still doesn’t work in Firefox 2, IE 6 and 7.

    design

    Let’s start with Firefox 2.

    Firefox 2 doesn’t support inline-block, but it does support a Mozilla specific display property ‘-moz-inline-stack’, which displays just like inline-block. And when we add it before display:inline-block, FF2 ignores that declaration and keeps -moz-inline-stack because it doesn’t support inline-block. Browsers that support inline-block will use it and ignore previous display property.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    <style>
        li {
            width: 200px;
            min-height: 250px;
            border: 1px solid #000;
            display: -moz-inline-stack;
            display: inline-block;
            vertical-align: top;
            margin: 5px;
        }
    </style>

    Unfortunately, it has a small bug:

    design

    Honestly, I don’t know what causes this bug. But there is quick fix. Wrap everything inside the < li> with a < div>.

    1
    2
    3
    4
    5
    6
    7
    
    <li>
            <div>
                <h4>This is awesome</h4>
                <img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
                alt="lobster" width="75" height="75"/>
            </div>
    </li>

    This seems to ‘reset’ everything inside the < li>’s and makes them display appropriately.

    design

    Now, on to IE 7. IE 7 does not support inline-block, but we can trick it into rendering the < li>s as if they were inline-block. How? hasLayout, a magical property of IE that allows for all sorts of fun! You can’t set hasLayout explicity on an element with hasLayout:true; or anything easy like that, but you can trigger it with other declarations like zoom:1.

    Technically, what hasLayout means is an element with hasLayout set to true is responsible for rendering itself and its children (combine that with a min-height and width, and you get something very similar to display:block). It’s kinda like magical fairy dust you can sprinkle on rendering issues and make them disappear.

    When we add zoom:1 and *display:inline (star hack to target IE6 & 7) to the < li>s, we make IE 7 display them as if they were inline-block:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    <style>
        li {
            width: 200px;
            min-height: 250px;
            border: 1px solid #000;
            display: -moz-inline-stack;
            display: inline-block;
            vertical-align: top;
            margin: 5px;
            zoom: 1;
            *display: inline;
        }
    </style>

    design

    IE 6 doesn’t support min-height, but thanks to its improper handling of the height property, we can use that instead. Setting _height (IE6 underscore hack) to 250px will give all < li>s a height of 250px, and if their content is bigger than that, they will expand to fit. All other browsers will ignore _height.

    So after all that work, here’s the final CSS and HTML:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    <style>
        li {
            width: 200px;
            min-height: 250px;
            border: 1px solid #000;
            display: -moz-inline-stack;
            display: inline-block;
            vertical-align: top;
            margin: 5px;
            zoom: 1;
            *display: inline;
            _height: 250px;
        }
    </style>
    1
    2
    3
    4
    5
    6
    7
    
    <li>
            <div>
                <h4>This is awesome</h4>
                <img src="http://farm4.static.flickr.com/3623/3279671785_d1f2e665b6_s.jpg"
                alt="lobster" width="75" height="75"/>
            </div>
    </li>
  •