Модульный север Javascript

Node.js внешний интерфейс JavaScript браузер

предисловие

С активным развитием веб-технологий и все более совершенной инфраструктурой интерфейсная сфера постепенно расширилась от браузеров до серверов (Node.js), настольных компьютеров (ПК, Android, iOS) и даже устройств Интернета вещей (IoT). Среди них JavaScript несет основную часть этих приложений.По мере того, как его масштаб и сложность увеличиваются в геометрической прогрессии, также устанавливается его система разработки программного обеспечения (совместная разработка, модульное тестирование, управление требованиями и дефектами и т. д.), модульное программирование становится все более насущной потребностью.

Поддержка модульного программирования в JavaScript еще не стала стандартом, и справиться с такой важной задачей трудно, на время рыцарский человек в реках и озерах шагнул вперед, преодолел все препятствия и перешел от рубящего и выжигающего к ориентированное на будущее модульное решение;

концепция

Модульное программирование заключается в реализации функций путем объединения некоторых __относительно независимых и повторно используемых модулей__.Две основные части: __определение модулей__ и __введение модулей__;

  • При определении модулей логика выполнения внутри каждого модуля не воспринимается внешним миром, а экспортируются (выставляются) только некоторые методы и данные;
  • При импорте модуля загружайте код для импорта синхронно/асинхронно, выполняйте и получайте открытые методы и данные;

рубить и сжигать

Хотя уровень языка JavaScript не обеспечивает модульного решения, использование его __объектно-ориентированных__ языковых функций, а также благословение __шаблона проектирования__ позволяет реализовать некоторые простые модульные архитектуры; классический случай. модуль и выставлять только часть информации в то место, где необходимо использовать модуль;

// 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();

Интуитивно объявление зависимостей и экспорт данных через Immediate Execution Function (IIFE) не сильно отличается от текущего модульного решения, но есть много важных характеристик, которые принципиально отличаются и не могут быть удовлетворены;

  • При определении модуля объявленные зависимости не принудительно импортируются автоматически, то есть перед определением модуля код зависимого модуля необходимо импортировать вручную;
  • Когда модуль определен, его код уже завершил процесс выполнения и не может быть загружен по требованию;
  • При использовании модулей в файлах вам необходимо смонтировать модуль в глобальную переменную (окно);

AMD и CMD делят мир

Отступление: из-за долгой истории эти два модульных решения постепенно сошли с исторической сцены, и конкретные характеристики подробно обсуждаться не будут;

Чтобы удовлетворить потребности эпохи «слэш-энд-бёрн», появились модульные спецификации AMD и CMD, которые решили потребности асинхронного модульного программирования на стороне браузера,Его основной принцип заключается в асинхронной загрузке модулей путем динамической загрузки сценариев и прослушивателей событий;

Две наиболее репрезентативные работы AMD и CMD соответствуют require.js и sea.js соответственно, основное отличие заключается во времени объявления зависимости и загрузки зависимости, среди них require.js выполняется в момент объявления по умолчанию, и sea.js уважает ленивую загрузку и нажатие, его нужно использовать; также стоит упомянуть, что метод написания спецификации CMD очень похож на метод CommonJS, и его можно использовать в CommonJS только с несколькими модификациями. Обратитесь к следующему случаю для лучшего понимания;

// 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

Первая версия Node.js была выпущена в 2009 г. CommonJS, как одна из основных фич, подходит для сценариев на стороне сервера; интерфейсная разработка, CommonJS широко используется в Node.js и браузерах;

// 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;

Технические характеристики

  • модуль (Объект): сам модуль
  • экспорт (*): экспортируемая часть модуля, то есть открытый контент.
  • require (функция): функция для загрузки модуля, получения экспортируемого значения целевого модуля (базовый тип — копия, ссылочный тип — неглубокая копия), вы можете загружать встроенные модули, модули npm и пользовательские модули.

выполнить

1. Определение модуля

По умолчанию любой файл .node .js .json является модулем, соответствующим спецификации;

2. Импортируйте модуль

Сначала прочитайте модуль из кеша (require.cache) сначала, если кеш не попал, выполняется анализ пути, а затем обрабатывается по разным типам модулей:

  • Встроенные модули, загружаемые прямо из памяти;
  • Внешние модули сначала выполняют адресацию и позиционирование файлов, затем компилируют и выполняют и, наконец, получают соответствующее значение экспорта;

В процессе компиляции Node упаковывает содержимое полученного файла JavaScript в начало и конец, и результаты следующие:

(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));
});

Обзор функций

  • Выполняйте объявление модуля и импортируйте логику синхронно и будьте внимательны при анализе некоторых сложных ссылок на зависимости (таких как циклические зависимости);
  • Механизм кэширования, лучшая производительность при ограничении использования памяти;
  • Модуль модуля очень гибок для модификации и может реализовать некоторые требования к настройке (например, горячее обновление, поддержка модуля любого типа файла);

Модуль ES (рекомендуется)

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 будетСтатический анализ кода, то есть модуль загружается во время компиляции кода, а зависимости определяются до выполнения (что может решить проблему циклических ссылок);
  • Ключевые слова модуля ES:import exportи уникальныйdefaultКлючевые слова для определения значения экспорта по умолчанию;
  • Значение, экспортируемое в модуль ES, представляет собой只读的值的引用, независимо от базового типа и сложного типа, а в CommonJS require — это копия значения, где сложный тип — это поверхностная копия значения;
// a.js
export let a = 1;
export function caculate() {
  a++;
};

// b.js
import { a, caculate } from 'a.js';

console.log(a); // 1
caculate();
console.log(a); // 2

a = 2; // Syntax Error: "a" is read-only

UMD

Совместимость с методом написания различных модульных спецификаций через слой самовыполняющихся функций, совместимость с модульными спецификациями, такими как AMD/CMD/CommonJS, вставка кода стоит тысячи слов, необходимо уделить особое внимание модулю ES, поскольку он будет анализировать статический код, поэтому это решение времени выполнения нельзя использовать, и в настоящее время оно совместимо с 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;
});

Реализация в инструментах сборки

Чтобы запустить модульный код в среде браузера, для упаковки необходимы некоторые инструменты модульной упаковки (в качестве примера возьмем веб-пакет).После определения записи проекта будет быстро выполнен анализ зависимостей, а затем все зависимые модули будут упакованный Преобразованный в совместимую с браузером реализацию соответствующей модульной спецификации;

Модульная база

Из приведенного выше вступления у нас есть определенное понимание его спецификации и реализации; в браузере для реализации спецификации CommonJS нам нужно только реализовать свойства модуля /exports/require/global, потому что браузер не может получить доступ к файловой системе , поэтому позиционирование файла в требуемом процессе необходимо преобразовать для загрузки соответствующего фрагмента 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, который не делает ничего, кроме динамического добавления тегов сценария, а затем обрабатывает их дальше через события onload/onerror.

2. Так как функция require полностью кастомизирована, мы можем реализовать больше возможностей в модуляризации, таких как модификация типов файлов, поддерживаемых расширениями require.resolve или Module._extensions, создание css/.jsx/.vue/images и т. д. Файлы также можно использовать для модульности;

Приложение 1: Список функций

Модульная спецификация Способ загрузки время загрузки Рабочая среда Примечание
AMD асинхронный Время выполнения браузер
CMD асинхронный Время выполнения браузер зависит отстатический анализ, модуль готов, когда требуется
CommonJS Синхронный Асинхронный Время выполнения Браузер/узел
ES Module Синхронный Асинхронный этап компиляции Браузер/узел Асинхронная загрузка через import()

Приложение 2: Ссылки