Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Analyse der JavaScript-Modularisierung

Eine kurze Analyse der JavaScript-Modularisierung

高洛峰
高洛峰Original
2017-02-04 16:24:581115Durchsuche

Vorwort

In Bezug auf die Modularisierung sind die von uns geschriebenen require- und import-Schlüsselwörter die direkteste Manifestation. Wenn Sie die relevanten Informationen überprüfen, werden Sie auf jeden Fall auf die Begriffe CommonJS, CMD AMD sowie RequireJS und SeaJS stoßen usw. Seltsamer Rahmen. Die offizielle Website von SeaJS beschreibt sich beispielsweise so: „Einfache und benutzerfreundliche Moduldefinitionsspezifikation, Sea.js folgt der CMD-Spezifikation. Natürliche und intuitive Codeorganisation, automatisches Laden von Abhängigkeiten …“

As Ich bin ehrlich gesagt ein Front-End-Neuling. Er sah verwirrt aus und konnte es nicht verstehen. Gemäß meinem üblichen Stil muss ich, bevor ich etwas vorstelle, immer erklären, warum es notwendig ist.

JavaScript-Grundlagen

Schüler, die auf der Clientseite arbeiten, sollten mit OCs #import „classname“, den Modul- und Dateimodifikatoren von Swift und dem Importpaket+Klassenmodus von Java vertraut sein. Wir sind an das Muster gewöhnt, dass der Verweis auf eine Datei auf eine Klasse verweist. In einer dynamischen Sprache wie JavaScript haben sich jedoch Dinge geändert. Zum Beispiel:







Hallo Wrold



// index.js
function onPress() {
var p = document.getElementById('hello');
p.innerHTML = 'Hello bestswifter';
}

The < Das script>-Tag in HTML kann als Import verstanden werden, sodass das onclick-Ereignis der Schaltfläche die in index.js definierte onPress-Funktion aufrufen kann.

Angenommen, wir stellen im Verlauf des Projekts fest, dass der angeklickte Text dynamisch generiert und von anderen JS-Dateien generiert werden muss, dann ist einfaches index.js nicht in der Lage, diese Aufgabe zu erledigen. Wir gehen davon aus, dass der generierte Inhalt in der math.js-Datei definiert ist:

// math.js
function add(a, b) {
return a + b;
}

Nach Ansicht des Kunden sollte die Datei index.js zu diesem Zeitpunkt wie folgt geschrieben werden:

// index.js
import „math.js“

function onPress () {
var p = document.getElementById('hello');
p.innerHTML = add(1, 2);
}

Leider unterstützt JavaScript die Importmethode nicht, was bedeutet, dass Methoden in anderen JS-Dateien nicht in einer JS-Datei referenziert werden können. Die richtige Lösung besteht darin, die Add-Methode direkt in index.js aufzurufen und auf math.js in index.html zu verweisen:





< /head>


Hallo Wrold





// index.js
function onPress() {
var p = document. getElementById('hello');
p.innerHTML = add(1, 2);
}

Sie können sehen, dass diese Schreibweise für Index.js nicht elegant ist Sie haben keine Kontrolle über den Inhalt in anderen JS-Dateien. Ob Sie die Add-Methode aufrufen können, hängt vollständig davon ab, ob Ihre eigene HTML-Datei korrekt auf andere JS-Dateien verweist.

Vorläufige Modularisierung

Die gerade genannten Schwachstellen können tatsächlich in zwei Typen unterteilt werden:

index.js kann nicht importiert werden und basiert auf HTML-Referenzen

Die Quelle der Add-Methode kann in index.js nicht unterschieden werden und das Konzept des Namespace fehlt.

Die erste Frage wird später beantwortet. Beginnen wir zunächst mit der zweiten Frage, z. B. dem Einfügen der Funktion in eine Objekt zuerst, damit wir ein Objekt verfügbar machen und Benutzern den Aufruf mehrerer Methoden dieses Objekts ermöglichen können:

//index.js
function onPress() {
var p = document.getElementById( ' hallo');
p.innerHTML = math.add(1, 2);
}

//math.js
var math = {
base: 0,
add: function(a, b) {
return a + b + base;
},
};

Sie können sehen, dass es bereits verfügbar ist index.js Geben Sie eine vereinfachte Version des Namespace an (d. h. math). Es gibt jedoch noch ein kleines Problem: Das Basisattribut wird beispielsweise der Außenwelt zugänglich gemacht und kann auch geändert werden. Eine bessere Möglichkeit besteht also darin, Mathematik in einem Abschluss zu definieren, um die internen Eigenschaften auszublenden:

// math.js
var math = (function() {
var base = 0;
return {
add: function(a, b) {
return a + b + base;
},
};
})();

Bisher haben wir die Definition und Verwendung von Modulen implementiert. Ein Kern der Modularisierung liegt jedoch im Namespace, was bedeutet, dass wir hoffen, dass unser Mathematikmodul nicht global ist, sondern bei Bedarf importiert wird. Selbst wenn mehrere Dateien Objekte mit demselben Namen verfügbar machen, gibt es keine Problem. Genau wie in node.js definiert das Modul, das verfügbar gemacht werden muss, seinen eigenen Exportinhalt, und dann verwendet der Aufrufer die Methode require.

Tatsächlich können Sie den Arbeitsmodus von node.js einfach simulieren und ihn lösen, indem Sie eine Zwischenschicht hinzufügen: Definieren Sie zunächst eine globale Variable:

// global.js
var module = {
exports: {}, // Wird zum Speichern aller bereitgestellten Inhalte verwendet
};

  Stellen Sie dann das Objekt in math.js bereit:

var math = ( function() {
var base = 0;
return {
add: function(a, b) {
return a + b + base;
},
} ;
})();

module.exports.math = math;

Benutzer index.js sollte jetzt sein:

var math = module . exports.math;

function onPress() {
var p = document.getElementById('hello');
// math
p.innerHTML = math.add(1, 2 );
}

Bestehende modulare Lösungen

Die obige einfache Modularisierungsmethode weist einige kleinere Probleme auf. Zunächst muss sich index.js strikt auf die Ausführung von math.js verlassen, da sich math.js erst nach der Ausführung beim globalen module.export registriert. Dies erfordert, dass Entwickler die Ladereihenfolge von JS-Dateien manuell verwalten. Mit zunehmender Projektgröße wird die Pflege von Abhängigkeiten immer komplexer.

Zweitens benötigen wir auch ein asynchrones On-Demand-Laden der JS-Datei, da der Browser beim Laden der JS-Datei das Rendern der Webseite stoppt.

Das letzte Problem besteht darin, dass die zuvor angegebene vereinfachte Modularisierungslösung den Modul-Namespace nicht löst. Derselbe Export ersetzt weiterhin den vorherigen Inhalt und die Lösung besteht darin, einen „Dateipfad< ;–> Export Contents“ beizubehalten " Tabelle und laden Sie sie basierend auf dem Dateipfad.

Basierend auf den oben genannten Anforderungen sind viele modulare Lösungen auf dem Markt erschienen. Warum es mehrere Standards gibt, liegt tatsächlich an den Eigenschaften des Frontends. Aufgrund des Fehlens eines einheitlichen Standards verlässt sich in vielen Fällen jeder auf Konventionen, wenn es um Dinge geht, wie zum Beispiel den oben genannten Export und Require. Wenn der Anbieter des Codes den Exportinhalt in module.exports speichert und der Benutzer module.export liest, ist das natürlich umsonst. Darüber hinaus sind auch die Implementierungsmethoden und Nutzungsszenarien jeder Spezifikation unterschiedlich.

CommonJS

Zu den bekannteren Spezifikationen gehören CommonJS, AMD und CMD. Die bekannten Frameworks Node.js, RequireJS und Seajs implementieren jeweils die oben genannten Spezifikationen.

Die früheste Spezifikation ist CommonJS, die von Node.js verwendet wird. Diese Spezifikation ähnelt unserem vorherigen Ansatz, der darin besteht, JS-Skripte synchron zu laden. Auf der Serverseite ist dies kein Problem, da die Dateien auf der Festplatte gespeichert sind. Die Eigenschaften des Browsers bestimmen jedoch, dass das JS-Skript asynchron geladen werden muss, da es sonst die Reaktion verliert, sodass die CommonJS-Spezifikation dies nicht kann direkt im Browser genutzt werden.

AMD 

Das berühmte Modulverwaltungstool Require.js auf der Browserseite wird asynchron geladen, lädt das JS-Skript über die Funktion importScripts(url); des Webworkers und führt dann den ursprünglich registrierten Rückruf aus . Die Schreibmethode von Require.js ist:

require(['myModule1', 'myModule2'], function (m1, m2){
// Hauptrückruflogik
m1.printName() ;
m2.printName();
});

Da diese beiden Module asynchron heruntergeladen werden, ist nicht sicher, welches Modul zuerst heruntergeladen und ausgeführt wird, aber es ist sicher dass das Hauptmodul zuerst heruntergeladen und ausgeführt wird. Der Rückruf muss ausgeführt werden, nachdem alle Abhängigkeiten geladen wurden.

Diese Art, Require.js zu schreiben, wird auch als Frontloading bezeichnet. Alle Abhängigkeiten müssen vor dem Schreiben der Hauptlogik angegeben werden, und diese Abhängigkeiten werden sofort asynchron geladen.

 Die von Require.js abgeleitete Spezifikation heißt AMD (Asynchronous Module Definition).

CMD

Ein weiteres hervorragendes Modulverwaltungstool ist Sea.js. Seine Schreibmethode ist:

define(function(require, exports, module) {
var foo = require('foo'); // Synchronisation
foo.add(1, 2);
...
require.async('math', function(math) { // Asynchronous
math.add(1, 2);
});
});

Sea.js wird auch Nearby Loading genannt. Aus der Art und Weise, wie es geschrieben ist, ist es offensichtlich um den Unterschied zu Require.js zu sehen. Wir können Abhängigkeiten nur dann deklarieren, wenn wir sie benötigen.

Wenn Sea.js auf eine Abhängigkeit stößt, lädt es nur die JS-Datei herunter und führt sie nicht aus. Stattdessen wartet es, bis alle abhängigen JS-Skripte heruntergeladen wurden, bevor es die Hauptlogik von Grund auf ausführt. Daher ist die Ausführungsreihenfolge abhängiger Module genau dieselbe wie die Schreibreihenfolge.

Die von Sea.js abgeleitete Spezifikation heißt CMD (Common Module Definition).

ES 6-Modularität

In ES6 verwenden wir das Schlüsselwort export, um Module zu exportieren, und das Schlüsselwort import, um Module zu referenzieren. Es ist zu beachten, dass dieser Satz von ES 6-Standards nicht in direktem Zusammenhang mit den aktuellen Standards steht und derzeit nur wenige JS-Engines ihn direkt unterstützen können. Daher übersetzt Babel tatsächlich den nicht unterstützten Import in den derzeit unterstützten Bedarf.

Obwohl es derzeit kaum einen Unterschied zwischen der Verwendung von import und require gibt (im Wesentlichen dasselbe), wird dennoch dringend empfohlen, das Schlüsselwort import zu verwenden, da die gesamte Implementierung erst einmal analysiert werden kann, wenn die JS-Engine das ES 6-Schlüsselwort import analysieren kann das Gleiche wie Große Veränderungen finden derzeit statt. Wenn Sie jetzt mit der Verwendung des Schlüsselworts import beginnen, werden die Codeänderungen in Zukunft sehr gering sein.

über: http://fullstack.blog/2017/01/25/JavaScript%20%E6%A8%A1%E5%9D%97%E5%8C%96%E7%AE%80% E8%BF%B0/

Weitere Artikel zur JavaScript-Modularisierungsanalyse finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn