Часто бывает так, что на вашем сайте есть куча небольших кусков javascript-кода. Одни отвечают за инициализацию тех или иных библиотек, другие навешивают события на элементы интерфейса, но всех их объединяет одно: они никак не связаны друг с другом.
Попробуем улучшить организацию нашего кода.
Например, возьмём код инициализации библиотеки подсветки синтаксиса:
# тут какие-то ещё функции
syntaxHighlighterInit = ->
$('pre code').each -> hljs.highlightBlock(this)
# выполняем нужные функции при событии ready
$ ->
# ...
syntaxHighlighterInit()
# выполняем нужные функции при событии page:load
$(document).on 'page:load', ->
# ...
syntaxHighlighterInit()
Господи, это ужасно, надеюсь никто так не пишет)
С точки зрения организации кода было бы разумно выделить каждый из таких отдельных кусков в свой небольшой модуль. Пусть у такого модуля будет функция инициализации, которая будет выполняться при событии ready (+ на page:load, если вы используете turbolinks). Такой модуль мог бы выглядеть, например, так:
# app/assets/javascripts/modules/syntax_highlighter.js.coffee
window.SyntaxHighlighter = {
init: ->
$('pre code').each ->
hljs.highlightBlock(this)
}
$ -> SyntaxHighLighter.init()
$(document).on 'page:load', SyntaxHighLighter.init()
Уже хорошо, но все ещё есть куда улучшить. В таком варианте придётся писать эти две нижние строчки для каждого нового модуля, а мы люди ленивые и забывчивые, так что давайте от этого избавляться.
Вынесем функционал инициализации всех модулей в отдельный объект - загрузчик модулей. Он должен хранить наши модули, выполнять их инициализацию и контролировать, чтобы они не инициализировались дважды.
# app/assets/javascripts/blog.js.coffee
window.Blog = window.Blog || do ->
modules = []
initialized = false
define = (name, module) ->
Blog[name] = Blog[name] || do ->
modules.push(name)
new_module = module()
new_module.init() if (Blog._initialized)
return new_module
return Blog[name]
init = ->
Blog[name].init() for name in modules
Blog._initialized = true
return {
_init: init,
define: define,
_modules: modules,
_initialized: initialized,
_registered: false
}
Blog._initialized = false;
$ ->
if (!Blog._registered)
$(document).ready(Blog._init)
$(document).on('page:load', Blog._init)
window.Blog._registered = true
Тот же модуль инициализации подсветки синтаксиса теперь выглядит так:
# app/assets/javascripts/modules/syntax_highlighter.js.coffee
Blog.define 'SyntaxHighlighter', ->
return{
init: ->
$('pre code').each ->
hljs.highlightBlock(this)
}