Heim  >  Artikel  >  Web-Frontend  >  Eine detaillierte Einführung in die Javascript-Modularität

Eine detaillierte Einführung in die Javascript-Modularität

不言
不言Original
2018-09-05 11:55:341617Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Einführung in die Javascript-Modularisierung. Freunde in Not können darauf verweisen.

Vorwort

Mit der rasanten Entwicklung der Webtechnologie und der zunehmenden Verbesserung der abhängigen Infrastruktur hat sich der Front-End-Bereich schrittweise vom Browser zum Server (Node.js) und Desktop erweitert ( Auf PCs, Android, iOS und sogar auf Geräten des Internets der Dinge (IoT) ist JavaScript der Kernbestandteil dieser Anwendungen. Da ihre Größe und Komplexität exponentiell zunehmen, werden auch ihre Software-Engineering-Systeme etabliert (kollaborative Entwicklung, Unit-Tests, Anforderungen usw.). Fehlermanagement etc.) wird der Bedarf an modularer Programmierung immer dringlicher.

JavaScripts Unterstützung für modulare Programmierung hat sich noch nicht zum Standard entwickelt, und es ist eine Zeit lang schwierig, diese wichtige Aufgabe zu übernehmen, und die Krieger haben alle Hindernisse überwunden und sind von der Brandrodung auf die Landwirtschaft übergegangen zu zukunftsweisenden modularen Lösungen;

Konzept

Modulare Programmierung besteht darin, Funktionen durch die Kombination einiger __relativ unabhängiger und wiederverwendbarer Module__ zu realisieren . Die beiden Kernteile sind __define module__ und __introduce module__;

  • Beim Definieren eines Moduls wird die Ausführungslogik innerhalb jedes Moduls von außen nicht wahrgenommen Daten;

  • Laden Sie beim Einführen eines Moduls den einzuführenden Code synchron/asynchron, führen Sie ihn aus und erhalten Sie seine bereitgestellten Methoden und Daten;

Slash and Burn

Obwohl JavaScript auf Sprachebene keine modulare Lösung bietet, kann es seine __objektorientierten__ Sprachfunktionen sowie __Designmuster_ _Blessing nutzen und eine einfache modulare Architektur realisieren Verwenden Sie den Singleton-Modus, um eine Modularisierung zu erreichen, die das Modul besser kapseln und nur einen Teil der Informationen an den Stellen verfügbar machen kann, an denen das Modul verwendet werden muss.

// Define a module
var moduleA = (function ($, doc) {
  var methodA = function() {};
  var dataA = {};
  return {
    methodA: methodA,
    dataA: dataA
  };
})(jQuery, document);

// Use a module
var result = moduleA.mehodA();

Intuitiv, indem die Funktion zur sofortigen Ausführung (IIFE) verwendet wird Abhängigkeiten deklarieren und Daten exportieren unterscheidet sich nicht wesentlich von der aktuellen modularen Lösung, unterscheidet sich jedoch wesentlich und weist einige wichtige Funktionen auf, die nicht erfüllt werden können Abhängigkeiten müssen nicht automatisch eingeführt werden, d. h. vor der Definition des Moduls muss der abhängige Modulcode manuell eingeführt werden

  • Wenn ein Modul definiert ist, ist sein Code bereits abgeschlossen Ausführungsprozess und kann nicht bei Bedarf geladen werden;

  • Wenn ein Modul dateiübergreifend verwendet wird, muss das Modul in eine globale Variable (Fenster) gemountet werden

  • AMD und CMD teilen die Welt

    Off-Topic: Im Laufe der Zeit sind diese beiden modularen Lösungen allmählich aus dem Stadium der Geschichte verschwunden, und die spezifischen Merkmale werden nicht im Detail besprochen;
  • Um die verbleibenden Anforderungen der „Slash-and-Burn“-Ära zu erfüllen, wurden die modularen Spezifikationen von AMD und CMD herausgebracht, um den Bedarf an asynchroner modularer Programmierung auf der Browserseite zu lösen. Das Kernprinzip besteht darin, Skripte asynchron zu laden dynamisch und ladende Module; __

Die beiden repräsentativsten Werke von AMD und Sea.js liegen im Zeitpunkt der Abhängigkeitsdeklaration und des Abhängigkeitsladens. unter denen require.js standardmäßig verwendet wird, wenn es deklariert wird Für die Ausführung befürwortet sea.js verzögertes Laden und die Verwendung bei Bedarf. Erwähnenswert ist auch, dass die Schreibmethode der CMD-Spezifikation der von CommonJS sehr ähnlich ist und in verwendet werden kann CommonJS mit nur geringfügigen Änderungen. Es ist einfacher zu verstehen, wenn man sich den folgenden Fall ansieht:

// AMD
define(['./a','./b'], function (moduleA, moduleB) {
  // 依赖前置
  moduleA.mehodA();
  console.log(moduleB.dataB);
  // 导出数据
  return {};
});
 
// CMD
define(function (requie, exports, module) {
  // 依赖就近
  var moduleA = require('./a');
  moduleA.mehodA();     

  // 按需加载
  if (needModuleB) {
    var moduleB = requie('./b');
    moduleB.methodB();
  }
  // 导出数据
  exports = {};
});

CommonJS

Im Jahr 2009 veröffentlichte Ty die erste Version von Node.js End-to-End-Szenarien; nach jahrelanger Prüfung und voller Unterstützung für Front-End-Engineering wird CommonJS häufig in

// Core Module
const cp = require('child_process');
// Npm Module
const axios = require('axios');
// Custom Module
const foo = require('./foo');

module.exports = { axios };
exports.foo = foo;

Standards verwendet >

Modul (Objekt): das Modul selbst

  • Exporte (*): der exportierte Teil des Moduls, also der offengelegte Inhalt

  • require (Funktion): Funktion zum Laden des Moduls und Abrufen des Exportwerts des Zielmoduls (der Basistyp ist eine Kopie, der Referenztyp ist eine flache Kopie), die integriert geladen werden kann Module, NPM-Module und benutzerdefinierte Module

  • Implementierung

    1. Moduldefinition
Standardmäßig ist jede .node .js .json-Datei ein Modul das entspricht der Spezifikation;

2. Modul importieren

Lesen Sie zuerst das Modul aus dem Cache (require.cache), führen Sie eine Pfadanalyse durch und verarbeiten Sie es dann nach verschiedenen Modultypen:

Eingebautes Modul, direkt aus dem Speicher laden

  • Externes Modul, führen Sie zuerst die Dateiadressierung und -positionierung durch , dann kompilieren und ausführen und schließlich den entsprechenden Exportwert erhalten;

  • Während des Kompilierungsprozesses umschließt Node den Inhalt der erhaltenen JavaScript-Datei.

    (function (exports, require, module, __filename, __dirname) {
        var circle = require('./circle.js');
        console.log('The area of a circle of radius 4 is ' + circle.area(4));
    });
    Funktionszusammenfassung

Synchronisierte Ausführung von Moduldeklarationen und Einführung von Logik und Vorsicht bei der Analyse einiger komplexer Abhängigkeitsreferenzen (z. B. zirkulärer Abhängigkeiten); >

Caching-Mechanismus, der eine bessere Leistung bietet und die Speichernutzung begrenzt
  • Modul ist äußerst flexibel für Änderungen und kann einige Anpassungsanforderungen erfüllen (z. B. Hot-Update, Modulunterstützung für jeden Dateityp);

ES Module(推荐使用)

ES Module 是语言层面的模块化方案,由 ES 2015 提出,其规范与 CommonJS 比之 ,导出的值都可以看成是一个具备多个属性或者方法的对象,可以实现互相兼容;但写法上 ES Module 更简洁,与 Python 接近;

import fs from 'fs';
import color from 'color';
import service, { getArticles } from '../service'; 

export default service;
export const getArticles = getArticles;

主要差异在于:

  • ES Module 会对静态代码分析,即在代码编译时进行模块的加载,在运行时之前就已经确定了依赖关系(可解决循环引用的问题);

  • ES Module 关键字:import export 以及独有的 default  关键字,确定默认的导出值;

  • ES Module 中导入模块的属性或者方法是强绑定的,包括基础类型;

UMD

通过一层自执行函数来兼容各种模块化规范的写法,兼容 AMD / CMD / CommonJS 等模块化规范,贴上代码胜过千言万语,需要特别注意的是 ES Module 由于会对静态代码进行分析,故这种运行时的方案无法使用,此时通过 CommonJS 进行兼容;

(function (global, factory) {
  if (typeof exports === 'object') {   
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    define(factory);
  } else {
    this.eventUtil = factory();
  }
})(this, function (exports) {
  // Define Module
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = 42;
});

构建工具中的实现

为了在浏览器环境中运行模块化的代码,需要借助一些模块化打包的工具进行打包( 以 webpack 为例),定义了项目入口之后,会先快速地进行依赖的分析,然后将所有依赖的模块转换成浏览器兼容的对应模块化规范的实现;

模块化的基础

从上面的介绍中,我们已经对其规范和实现有了一定的了解;在浏览器中,要实现 CommonJS 规范,只需要实现 module / exports / require / global 这几个属性,由于浏览器中是无法访问文件系统的,因此 require 过程中的文件定位需要改造为加载对应的 JS 片段(webpack 采用的方式为通过函数传参实现依赖的引入)。具体实现可以参考:tiny-browser-require。

webpack 打包出来的代码快照如下,注意看注释中的时序;

(function (modules) {
  // The module cache
  var installedModules = {};
  // The require function
  function __webpack_require__(moduleId) {}
  return __webpack_require__(0); // ---> 0
})
({
  0: function (module, exports, __webpack_require__) {
    // Define module A
    var moduleB = __webpack_require__(1); // ---> 1
  },
  1: function (module, exports, __webpack_require__) {
    // Define module B
    exports = {}; // ---> 2
  }
});

实际上,ES Module 的处理同 CommonJS 相差无几,只是在定义模块和引入模块时会去处理 __esModule 标识,从而兼容其在语法上的差异。

异步和扩展

1、浏览器环境下,网络资源受到较大的限制,因此打包出来的文件如果体积巨大,对页面性能的损耗极大,因此需要对构建的目标文件进行拆分,同时模块也需要支持动态加载;

webpack 提供了两个方法 require.ensure() 和 import() (推荐使用)进行模块的动态加载,至于其中的原理,跟上面提及的 AMD & CMD 所见略同,import() 执行后返回一个 Promise 对象,其中所做的工作无非也是动态新增 script 标签,然后通过 onload / onerror 事件进一步处理。

2、由于 require 函数是完全自定义的,我们可以在模块化中实现更多的特性,比如通过修改 require.resolve 或 Module._extensions 扩展支持的文件类型,使得 css / .jsx / .vue / 图片等文件也能为模块化所使用;

附录:特性一览表

模块化规范 加载方式 加载时机 运行环境 备注
AMD 异步 运行时 浏览器
CMD 异步 运行时 浏览器
CommonJS 同步/异步 运行时 浏览器 / Node
ES Module 同步/异步 编译阶段 浏览器 / Node 通过 import() 实现异步加载

相关推荐:

javascript模块化编程(转载),javascript模块化

JavaScript模块化思想

Das obige ist der detaillierte Inhalt vonEine detaillierte Einführung in die Javascript-Modularität. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen 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