12 Stimmen

Organisation und Leistung von jQuery-Code

Nachdem ich einige Nachforschungen zu diesem Thema angestellt habe, habe ich viel mit Mustern experimentiert, um meinen jQuery-Code zu organisieren (Rebecca Murphy hat eine Präsentation auf der jQuery-Konferenz zum Beispiel).

Gestern habe ich das (aufschlussreiche) Modulmuster überprüft. Das Ergebnis erinnert ein wenig an das YUI Syntax, denke ich:

//global namespace MyNameSpace
if(typeof MNS=="undefined"||!MNS){var MNS={};}

//obfuscate module, just serving as a very simple example
MNS.obfuscate = function(){
    //function to create an email address from obfuscated '@'
    var email = function(){
        $('span.email').each(function(){
            var emailAddress = $(this).html().replace(' [ @ ] ','@');
            $(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');

        });
    };    
    return {
        email: email
    };    
}();

//using the module when the dom's ready
jQuery(document).ready(function($){
    MNS.obfuscate.email();
});

Am Ende hatte ich mehrere Module. Einige enthielten natürlich "private members", was in diesem Fall bedeutet, dass Variablen und/oder Funktionen, die nur für andere Funktionen innerhalb dieses Moduls von Bedeutung waren, nicht in der Rückgabeanweisung landeten.

Ich dachte, dass es sinnvoll ist, zusammenhängende Teile meines Codes (z.B. alles, was mit der Suche zu tun hat) in einem Modul zusammenzufassen, um dem Ganzen Struktur zu geben.

Aber nachdem ich dies geschrieben hatte, las ich einen Artikel von John (Resig), wo er auch über die Leistung des Modulmusters schreibt:

"Die Instanziierung einer Funktion mit einer Reihe von Prototyp-Eigenschaften ist sehr, sehr schnell. Damit ist das Modul-Muster und Ähnliches völlig überflüssig. Wenn Sie also eine Funktion haben, auf die häufig zugegriffen wird (die ein Objekt zurückgibt) und mit der die Benutzer interagieren sollen, dann ist es von Vorteil, wenn die Objekteigenschaften in der Prototypenkette enthalten sind und die Funktion instanziiert wird. Hier ist es, in Code:

// Very fast
function User(){}
    User.prototype = { /* Lots of properties ... */ };

// Very slow
function User(){
    return { /* Lots of properties */ };
}

(John erwähnt, dass er nicht gegen das Modulmuster "per se" ist - nur damit Sie es wissen :)

Dann war ich mir nicht mehr sicher, ob ich mit meinem Code in die richtige Richtung ging. Die Sache ist die: Ich weiß nicht wirklich brauchen keine privaten Mitglieder, und ich glaube auch nicht, dass ich vorerst Vererbung brauche. Alles, was ich im Moment will, ist ein lesbares/wartbares Muster. Ich schätze, dass dies bis zu einem gewissen Grad auf persönliche Vorlieben hinausläuft, aber ich möchte nicht mit lesbarem Code enden, der (ziemlich ernste) Leistungsprobleme hat.

Ich bin kein JavaScript-Experte und daher noch weniger ein Experte, wenn es um Leistungstests geht. Zunächst einmal weiß ich also nicht, inwieweit die von John erwähnten Dinge ("häufig genutzte Funktion (die ein Objekt zurückgibt), mit der die Benutzer interagieren sollen", viele Eigenschaften usw.) auf meinen Code zutreffen. Die Dokumente, mit denen mein Code interagiert, sind nicht riesig, mit 100er oder 1000er von Elementen. Vielleicht ist das also gar kein Problem.

Aber eine Sache, die mir in den Sinn gekommen ist, ist, dass man statt nur

$('span.email').each(function(){
    var emailAddress = $(this).html().replace(' [ @ ] ','@');
    $(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});

(innerhalb der domready-Funktion) erstelle ich zwei "zusätzliche" Funktionen, obfuscate und email, aufgrund der Verwendung des Modulmusters. Die Erstellung der zusätzlichen Funktionen kostet etwas Zeit. Die Frage ist: Ist dieser Aufwand in meinem Fall messbar?

Ich bin nicht sicher, ob eine Schließung in meinem Beispiel oben erstellt wird (in einem interessanten Beitrag auf dem jQuery-Forum las ich das folgende: "Es gibt eine philosophische Debatte darüber, ob eine innere Funktion eine Closure erzeugt, wenn sie nichts auf ein variables Objekt einer äußeren Funktion referenziert..."), aber ich hatte Closures in meinem echten Code. Und obwohl ich nicht glaube, dass ich dort irgendwelche zirkulären Referenzen hatte, weiß ich nicht, inwieweit dies zu hohem(er) Speicherverbrauch/Problemen mit der Garbage Collection führen könnte.

Ich würde wirklich gerne Ihren Beitrag dazu hören und vielleicht einige Beispiele Ihres Codes sehen. Und welche Tools bevorzugen Sie, um Informationen über Ausführungszeit, Speicher- und CPU-Auslastung zu erhalten?

7voto

bobince Punkte 512550

Ich glaube auch nicht, dass ich im Moment eine Erbschaft brauche.

In der Tat. Dies gilt nicht wirklich für die Verwendung von Modulen als Namespace. Es geht um Klasseninstanz-Analogien.

Objekte, die Sie erstellen, indem Sie jede Instanz aus einer völlig neuen {name: member} Objekt sind weniger effizient als Objekte, die Sie mit new Class con Class.prototype.name= member . Im Fall des Prototyps ist die member Wert gemeinsam genutzt wird, was zu leichteren Instanzen führt.

In Ihrem Beispiel MNS ist ein Singleton, so dass die gemeinsame Nutzung von Mitgliedern durch einen Prototyp keine Vorteile bringt.

Ich bin nicht sicher, ob in meinem obigen Beispiel ein Abschluss erstellt wird

Ja, das ist sie. Auch wenn in der äußeren Funktion keine Variablen definiert sind, werden für die äußere Funktion ein LexicalEnvironment- und ein Scope-Objekt erstellt, mit this y arguments darin gebunden. Eine clevere JS-Engine könnte in der Lage sein, es weg zu optimieren, da jede innere Funktion verstecken muss this y arguments mit ihren eigenen Kopien, aber ich bin nicht sicher, dass eine der aktuellen JS-Implementierungen tatsächlich tun, dass.

Der Leistungsunterschied sollte in jedem Fall nicht nachweisbar sein, da Sie nichts Wesentliches in die Argumente einbringen. Für ein einfaches Modulmuster schadet es meiner Meinung nach nicht.

Und welche Tools bevorzugen Sie, um Informationen über Ausführungszeit, Speicher- und CPU-Nutzung zu erhalten?

Der Anfang ist einfach, den Code 10000 Mal in einer for-Schleife auszuführen und zu sehen, wie viel größer new Date().getTime() hat, mehrmals auf so vielen verschiedenen Browsern ausgeführt, wie Sie zur Verfügung haben.

$(this).html().replace(' [ @ ] ','@');

(Wozu soll das gut sein? Im Moment wird der HTML-Code des Bereichs in eine neue String ersetzen Sie nur die erste Instanz von [ @ ] con @ und geben eine neue String Wert. Der vorhandene Inhalt im DOM wird nicht verändert).

1voto

Pointy Punkte 387467

Wie viel Javascript haben Sie? Meiner Erfahrung nach, auf Websites mit Lose von Javascript-Code auf den Seiten, Leistungsprobleme kommen in der Regel von Code, der tatsächlich する Dinge. Im Allgemeinen rühren die Probleme daher, dass man versucht, zu viele Dinge zu tun, oder dass man versucht, eine bestimmte Sache wirklich schlecht zu machen. Ein Beispiel wäre der Versuch, Handler an Elemente in Tabellenzeilen (große Tabellen) zu binden, anstatt etwas wie "live" zu verwenden.

Ich will damit sagen, dass die Art und Weise, wie Ihre Module oder Funktionen oder was auch immer organisiert werden, mit ziemlicher Sicherheit keine wirklichen Leistungsprobleme auf Ihren Seiten verursachen wird. Was motiviert Sie dazu, sich all diese Mühe zu machen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X