[JS] Optimalisatie "external links" script

Pagina: 1
Acties:

  • Victor
  • Registratie: November 2003
  • Niet online
Ik ben bezig een simpel scriptje te schrijven dat alle anchors op een pagina naloopt en controleert of ze toevallig naar een externe site wijzen. Indien dit het geval is, wordt de anchor gemarkeerd in de vorm van een icoontje naast de tekst en opent de pagina in een nieuw venster (met fallback naar het huidige venster als een popupblocker roet in het eten gooit).

Allereerst, het script zoals het er nu bijstaat:
JavaScript:
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
function newWindow() {
    return !window.open(this.href, "_blank");
}

function externalLinks() {
    // Regular expressions, match should be negative
    var hrefRegEx = new RegExp("^mailto:|(http|https)://" + window.location.hostname, "gi"),
        classRegEx = new RegExp("nopopup", "gi");

    // Anchors
    var anchors = document.getElementsByTagName("a"),
        i = anchors.length;

    // Icon
    var icon = document.createElement("img");
    icon.src = "external.gif";
    icon.alt = "Opent in een nieuw venster";

    // Check if the anchor points to an external URI
    function check(anchor) {
        if (anchor.href && !anchor.href.match(hrefRegEx) && !anchor.className.match(classRegEx)) {
            anchor.onclick = newWindow;
            anchor.title = (!anchor.title ? "Opent in een nieuw venster" : anchor.title + " (Opent in een nieuw venster)");

            // If the anchor contains an image, don't add the icon
            if (!anchor.getElementsByTagName("img").length) {
                anchor.appendChild(icon.cloneNode(false));
            }
        }
    }

    // Loop-tee-loop
    while(i--) {
        check(anchors[i]);
    }
}


Nu is dit een relatief eenvoudig script, maar wel één dat zich leent voor allerlei optimalisatie technieken en truuks. Aangezien ik hier toch eens serieus naar wilde kijken, heb ik dus geprobeerd dit script zo efficiënt mogelijk te maken.

Wat heb ik gedaan?
1) Zoveel mogelijk buiten de loop gehouden. Reguliere expressies niet als literal argument aan de match methodes meegeven, event handler volledig buiten de functie plaatsen om eventuele closure problemen te voorkomen, etc.

2) Het aantal DOM calls tot een minimum beperken. Verder zoveel mogelijk cachen.

3) De loop reversen. Ik heb ook een "Duff's device" geprobeerd, maar haalde hier geen meetbare snelheidswinst mee.

Nu de vraag, wat kan er beter? Wellicht dat het toevoegen van het icoon sneller kan. Ik had het aanvankelijk met CSS opgelost, maar dat bleek fout te gaan in IE (kan niet lekker overweg met backgrounds op een inline element dat meerdere tekstregels bevat).

Nu hoef ik niet direct specifieke tips voor dit script, ik ben vooral geïnteresseerd in wat algemene richtlijnen om m'n JavaScripts zo efficiënt mogelijk hun werk te laten doen.


Overigens nog één laatste, ietwat nasty idee waar ik mee speel: het aanroepen van de externalLinks functie op de volgende manier:
JavaScript:
1
setTimeout(externalLinks, 0);

Als ik me niet vergis wordt code die aangeroepen wordt door setTimeout in een andere thread uitgevoerd. Op deze manier zou ik kunnen voorkomen dat de pagina "bevriest" terwijl er door de +/- 200 anchors geloopt wordt. Als ik het test merk ik wel dat de pagina niet meer bevriest (alleen merkbaar overigens bij 1000+ anchors). Klopt het dat de functie in een andere thread wordt uitgevoerd? En kleven er nog nadelen aan dit idee?

  • chris
  • Registratie: September 2001
  • Laatst online: 11-03-2022
Het ziet er behoorlijk efficient uit. Zorg dat je je algoritmen kent als je goede code wil schrijven, en voor javascript is het handig om de quirks van de browsers te kennen. Zo kan IE bijvoorbeeld erg snel renderen, en is de javascript-performance van Mozila weer veel sneller. String-concatenatie is in IE heel duur, in Mozila vrij goedkoop. De truc is om een string-concatenator te bouwen, die alle strings in een array bijhoud en op het laaste moment een join doet.

Hier ben je vast niet naar op zoek, maar toch nog een advies: probeer niet te snel gaan optimaliseren. Alleen als het echt nodig is.

Over de setTimeout: dat is inderdaad heel handig, zeker als je pagina er niet meer door bevriest. Het nadeel er van (in het algemeen) is dat er geen communicatie meer mogelijk is met je originele thread. Het zijn trouwens niet echt threads zoals meestal gebruikt: er wordt altijd maar een "thread" tegelijk uitgevoerd.