Почему автозагрузка, load_all! и требуют, чтобы все они использовались в active_support.rb?

Я смотрел active_support.rb, чтобы понять, какой процесс загрузки он использует. Он использует три метода загрузки: load_all!, autoload и require. Зачем использовать три разных способа загрузки в одном файле?

module ActiveSupport
  def self.load_all!
    [Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte, SecureRandom, TimeWithZone]
  end

  autoload :BacktraceCleaner, 'active_support/backtrace_cleaner'
  autoload :Base64, 'active_support/base64'
  autoload :BasicObject, 'active_support/basic_object'
  autoload :BufferedLogger, 'active_support/buffered_logger'
  autoload :Cache, 'active_support/cache'
  autoload :Callbacks, 'active_support/callbacks'
  autoload :Deprecation, 'active_support/deprecation'
  autoload :Duration, 'active_support/duration'
  autoload :Gzip, 'active_support/gzip'
  autoload :Inflector, 'active_support/inflector'
  autoload :Memoizable, 'active_support/memoizable'
  autoload :MessageEncryptor, 'active_support/message_encryptor'
  autoload :MessageVerifier, 'active_support/message_verifier'
  autoload :Multibyte, 'active_support/multibyte'
  autoload :OptionMerger, 'active_support/option_merger'
  autoload :OrderedHash, 'active_support/ordered_hash'
  autoload :OrderedOptions, 'active_support/ordered_options'
  autoload :Rescuable, 'active_support/rescuable'
  autoload :SecureRandom, 'active_support/secure_random'
  autoload :StringInquirer, 'active_support/string_inquirer'
  autoload :TimeWithZone, 'active_support/time_with_zone'
  autoload :TimeZone, 'active_support/values/time_zone'
  autoload :XmlMini, 'active_support/xml_mini'
end

require 'active_support/vendor'
require 'active_support/core_ext'
require 'active_support/dependencies'
require 'active_support/json'

I18n.load_path << "#{File.dirname(__FILE__)}/active_support/locale/en.yml"

Ответ 1

Я точно не знаю, почему Rails использует три разных метода загрузки (фактически два - см. ниже). Но я знаю, в общем, почему кто-то может.

Require означает "загрузить это прямо сейчас". autoload означает "загрузить это, когда вам нужно его использовать". Обычная причина использования обоих заключается в том, что у вас есть некоторые файлы, которые вы в значительной степени предполагаете, будут использоваться в каждом вызове программы; и другие, которые являются необязательными. Например, в приложении Rails, которое не использует устаревшие методы, вам никогда не понадобится Deprecation; поэтому зачем замедлять первоначальную настройку, загружая этот файл?

В других случаях вы можете различать файлы, которые понадобятся на ранней стадии выполнения программы, и файлы, которые могут подождать. Например, вам вряд ли понадобится Gzip до тех пор, пока не поступит первый запрос. Таким образом, используя автозагрузку, вы можете сократить время от первоначальной настройки за счет небольшого замедления для первого запроса.

Вы могли бы спросить, ну, почему бы просто не использовать autoload для всего? Зачем загружать все, что нужно? Одна из причин заключается в том, что автозагрузка работает только для констант. Так, например, active_support/core_ext добавляет кучу методов в числовой, чтобы вы могли писать код типа 3.days, 6.minutes и 16.seconds.ago. В 3.days нет константы, поэтому вы не можете запускать автозагрузку в этом выражении. (И вы не можете автозагрузить Numeric, потому что базовый класс уже загружен - это просто расширения, которые вы хотите добавить.)

Наконец, этот класс фактически не использует три метода загрузки; он использует два и предоставляет один (вид). load_all! используется Rails::Initializer to

# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything loaded before forking and
# to avoid autoload race conditions in JRuby.

Я не знаю подробностей, и я не знаю, почему эти конкретные модули предварительно загружены (а не другие). Но поскольку это предназначено для поддержки определенных сред, вы можете понять, почему это может потребовать от кода отдельно от механизма загрузки по умолчанию.

Ответ 2

Метод rubi autoload может использоваться для связывания константы с именем файла, которое будет загружено при первом обращении к указанной константе. Это не позволяет загружать всю структуру при запуске.

Похоже, что метод load_all! вызывается из рельсов initializer.rb и используется для предварительной загрузки всех фреймворков, которые настроены на предварительную загрузку. Это работает путем вызова каждого метода framework load_all!, который просто ссылается на массив констант... который запускает автозагрузку.

В соответствии с комментариями в initializer.rb для preload_frameworks...

# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything loaded before forking and
# to avoid autoload race conditions in JRuby.

require - загрузить основные требуемые файлы для конкретной структуры.