Когда функция неоднократно вызывается с одними и теми же параметрами, и каждый раз возвращает для этих параметров одинаковый результат, то можно сохранить его и сразу возвращать без долгих вычислений.
В библиотеке Underscore.js есть метод, который для любой функции делает версию этой функции с кешированием — memoize.
Так, например, её можно применять для кеширования _.template()
.
var View = Backbone.View.extend({
render: function () {
var markup = _.template(this.template, this.model.toJSON());
this.$el.html(markup);
}
});
Вместо того, чтобы при каждом обновлении данных компилировать тектовый шаблон , он будет преобразован в функцию только при первом использовании. А все последующие вызовы будут использовать уже скомпилированный вариант.
var cachedTemplate = _.memoize(_template);
var View = Backbone.View.extend({
render: function () {
var markup = cachedTemplate(this.template, this.model.toJSON());
this.$el.html(markup);
}
});
Разница в производительности при рендеринге простенького шаблона и его кешированного варианта налицо.
Все скомпилированные шаблоны находятся в хранилище ключ-значение внутри замыкания
_.memoize()
. Ключом в нашем случае выступает текст шаблона, а значением — скомпилированная функция.
В качестве ключа может быть не только текстовая строка. Если первый параметр кешируемой функции не является строкой, то ключом станет то, что венёт его метод .toString()
. В некоторых случаях это может оказаться неприемлемо (например, когда первым аргументом идёт объект). Чтобы избежать коллизий, в _.memoize()
можно передать опциональную функцию, генерирующую ключ из аргументов.
var cachedTemplate = _.memoize(_.template, function (value) {
return JSON.stringify(value);
});
Аналогичный приём, но без использования Underscore.js я применяю для кеширования асинхронных запросов.