предисловие
С активным развитием веб-технологий и все более совершенной инфраструктурой интерфейсная сфера постепенно расширилась от браузеров до серверов (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: Ссылки
- Технические характеристики модуля AMD:GitHub.com/АМД ЕСТЬ/АМД ЕСТЬ…
- Спецификация определения модуля CMD:GitHub.com/морской JS/морской JS…
- Документация для модулей веб-пакета:Веб-пакет. Просто .org/concepts/mo…
- Принцип и реализация браузерной загрузки модулей CommonJS:Уууу. Руан Ифэн.com/blog/2015/0…