Выразительный JavaScript (Хавербеке) - страница 110

Вторая проблема – модуль не может экспортировать переменную напрямую, только через объект >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) {