Вторая проблема – модуль не может экспортировать переменную напрямую, только через объект >export
. К примеру, модулю может потребоваться экспортировать только конструктор объекта, объявленного в нём. Сейчас это невозможно, поскольку >require
всегда использует объект >exports
в качестве возвращаемого значения.
Традиционное решение – предоставить модули с другой переменной, >module
, которая является объектом со свойством >exports
. Оно изначально указывает на пустой объект, созданный >require
, но может быть перезаписано другим значением, чтобы экспортировать что-либо ещё.
>function require(name) {
> if (name in require.cache)
> return require.cache[name];
> var code = new Function("exports, module", readFile(name));
> var exports = {}, module = {exports: exports};
> code(exports, module);
> require.cache[name] = module.exports;
> return module.exports;
>}
>require.cache = Object.create(null);
Сейчас у нас есть система модулей, использующих одну глобальную переменную >require
, чтобы позволять модулям искать и использовать друг друга без выхода в глобальную область видимости.
Такой стиль системы модулей называется >CommonJS
, по имени псевдостандарта, который первым его описал. Он встроен в систему Node.js. Настоящие реализации делают гораздо больше описанного мною. Главное, что у них есть более умный способ перехода от имени модуля к его коду, который разрешает загружать модули по относительному пути к файлу, или же по имени модуля, указывающему на локально установленные модули.
Медленная загрузка модулей
Хотя и возможно использовать стиль CommonJS для браузера, но он не очень подходит для этого. Загрузка файла из Сети происходит медленнее, чем с жёсткого диска. Пока скрипт в браузере работает, на сайте ничего другого не происходит (по причинам, которые станут ясны к 14 главе). Значит, если бы каждый вызов >require
скачивал что-то с дальнего веб-сервера, страница бы зависла на очень долгое время при загрузке.
Можно обойти это, запуская программу типа Browserify с вашим кодом перед выкладыванием её в веб. Она просмотрит все вызовы >require
, обработает все зависимости и соберёт нужный код в один большой файл. Веб-сайт просто грузит этот файл и получает все необходимые модули.
Второй вариант – оборачивать код модуля в функцию, чтобы загрузчик модулей сначала грузил зависимости в фоне, а потом вызывал функцию, инициализирующую модуль, после загрузки зависимостей. Этим занимается система AMD (асинхронное определение модулей).
Наша простая программа с зависимостями выглядела бы в AMD так:
>define(["weekDay", "today"], function(weekDay, today) {