Оптимальное ООП с Google Closure Compiler
В javascript есть несколько основных стилей объявления объектов и свойств.
Они основаны на разной структуре кода, и поэтому - по-разному сжимаются компилятором.
Цель этой статьи - выбрать наилучший стиль ООП с точки зрения минификации кода и понять, почему ООП в таком стиле сжимается лучше всего.
Сжатие будет осуществляться продвинутым способом: --compilation_level ADVANCED_OPTIMIZATIONS .
Мы рассмотрим различные варианты ООП для виджета SayWidget с двумя приватными методами init, setElemById и публичным методом setSayHandler .
Кроме того, для проверки, как работает удаление недостижимого кода, в виджете будет присутствовать неиспользуемый метод unused
Первый стиль ООП основывается на классическом механизме наследования javascript, при котором свойства и методы берутся из прототипа.
function SayWidget(id) {
this.setElemById(id)
this.init()
}
SayWidget.prototype = {
init: function() {
this.elem.style.display = 'none'
},
setElemById: function(id) {
this.elem = document.getElementById(elem)
},
setSayHandler: function() {
this.elem.onclick = function() {
alert('hi')
}
},
unused: function() { alert("unused") }
}
window['SayWidget'] = SayWidget
SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler
Результат сжатия:
function a(b) {
this.c(b);
this.b()
}
a.prototype = {b:function() {
this.a.style.display = "none"
}, c:function() {
this.a = document.getElementById(elem)
}, d:function() {
this.a.onclick = function() {
alert("hi")
}
}};
window.SayWidget = a;
a.prototype.setSayHandler = a.prototype.d;
Как видно, все свойства. кроме экстернов, были заменены на короткие.
Что очень кстати, был удален неиспользуемый метод unused .
Этот метод, в принципе, аналогичен предыдущему, но методы добавляются в прототип по одному.
function SayWidget(id) {
this.setElemById(id)
this.init()
}
SayWidget.prototype.init = function() {
this.elem.style.display = 'none'
}
SayWidget.prototype.setElemById = function(id) {
this.elem = document.getElementById(id)
}
SayWidget.prototype.setSayHandler = function() {
this.elem.onclick = function() {
alert('hi')
}
}
SayWidget.prototype.unused = function() { alert("unused") }
window['SayWidget'] = SayWidget
SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler
После сжатия:
function a(b) {
this.a = document.getElementById(b);
this.a.style.display = "none"
}
a.prototype.b = function() {
this.a.onclick = function() {
alert("hi")
}
};
window.SayWidget = a;
a.prototype.setSayHandler = a.prototype.b;
А здесь - уже интереснее. Благодаря тому, что каждая функция описана отдельно, Google Closure Compiler может построить граф взаимодействий и заинлайнить функции. Что и произошло: в прототипе осталась только одна функция a.prototype.b (бывшая setSayHandler ).
В результате размер существенно уменьшился.
Это - концептуально другой подход: методы записываются не в прототип, а в сам объект во время создания. При этом приватные свойства и методы являются локальными переменными функции-конструктора.
В следующем коде находится два неиспользуемых метода unused : один публичный и один - приватный.
function SayWidget(id) {
var elem
setElemById(id)
init()
function init() {
elem.style.display = 'none'
}
function setElemById(id) {
elem = document.getElementById(id)
}
function unused() {
alert("unused")
}
this.setSayHandler = function() {
elem.onclick = function() {
alert('hi')
}
}
this.unused = function() {
alert("unused")
}
}
window['SayWidget'] = SayWidget
После сжатия:
function b(c) {
function d() {
a.style.display = "none"
}
function e(f) {
a = document.getElementById(f)
}
var a;
e(c);
d();
this.a = function() {
a.onclick = function() {
alert("hi")
}
};
this.b = function() {
alert("unused")
}
}
window.SayWidget = b;
Этот стиль ООП обычно сжимается лучше прототипного, т.к. обычный компрессор (или Google Closure Compiler в безопасном режиме) сжимает только локальные переменные.
Но продвинутый режим Google Closure Compiler уравнивает локальные переменные с обычными (кроме экстернов) - он сжимает и то и другое.
Поэтому никакого преимущества этот стиль ООП не показал. Более того, в данном компилятору не удалось ни заинлайнить вызовы ни удалить неиспользуемый публичный метод.
Последний из рассматриваемых стилей работает без вызова оператора new. Он просто возвращает объект с нужными методами.
// object = sayWidget(id)
function sayWidget(id) {
var elem
setElemById(id)
init()
function init() {
elem.style.display = 'none'
}
function setElemById(id) {
elem = document.getElementById(id)
}
function unused() {
alert("unused")
}
var me = { // новый объект
setSayHandler: function() {
elem.onclick = function() {
alert('hi')
}
},
unused: function() {
alert("unused")
}
}
me['setSayHandler'] = me.setSayHandler
return me
}
window['sayWidget'] = sayWidget
После сжатия:
function c(a) {
function d() {
b.style.display = "none"
}
function e(f) {
b = document.getElementById(f)
}
var b;
e(a);
d();
a = {a:function() {
b.onclick = function() {
alert("hi")
}
}, b:function() {
alert("unused")
}};
a.setSayHandler = a.a;
return a
}
window.sayWidget = c;
Результат аналогичен предыдущему.
Победил в итоге, вот сюрприз, самый длинный способ - добавление каждого свойства через прототип кодом вида: SayWidget.prototype.methodXXX = ... .
Более того, эта победа не случайна. Такой способ позволяет компилятору построить самый полный граф взаимодействий и произвести инлайны.
А определение функций в прототипе вместо замыкания - дает возможность успешно вырезать неиспользуемые символы. В результате - уменьшение размера кода.
В библиотеке Google Closure Library, под которую заточен Closure Compiler, используется именно такой стиль объявления свойств.
|
На самом деле можно еще описать класс в таком стиле:
var oop = {};
(function (ns){
function KeyType() {}
/**
* @constructor
*/
function TestObject() {
this._markedObj = new KeyType()
}
TestObject.prototype = {
_markedObj : null,
doIt: function() {
opns.addEvent("keydown", function(obj) {
return obj instanceof KeyType
})
},
getMarked: function() {
return this._markedObj
},
dummy: function(event) {
opns.isEvent(event)
}
}
/* export TestObject */
ns.TestObject = TestObject
})(oop)
В данной записи пространство имен oop будет содержать "публичный" класс TestObject, который в свою очередь использует "приватный" класс KeyType. В данном случае closure сможет убрать, к примеру, метод dummy, если он не используется. И вообще, похоже, closure сможет выполнить все оптимизации за исключением одной - вызов функции вводящей определение TestObject не будет заинлайнен.
У приведенного кода есть только одно преимущество перед описанным добавлением через прототип - этот способ позволяет вводить приватные сущности, используемые публично видимыми классами (типа KeyType в описанном примере).
К слову
a.prototype.b = ...;
a.prototype.setSayHandler = a.prototype.b;
- не полный аналог
a.prototype.setSayHandler = ...;
Полный аналог выглядел бы так:
a.prototype.b = ...;
a.prototype.setSayHandler = a.prototype.b;
delete a.prototype.b; // <<<<<
Короче, GCC не просто переименовывает свойства, а дублирует их, что теоретически может выйти боком, когда свойства по ходу дела меняются, или когда делается перебор свойств (например, для сериализации).
А что же делать, если unused - мое API в конструкторе для объекта, и самим объектом не используется, но используется внешним (либо другим js-кодом, либо даже flash'ом)? Получается он его похерит
окончательная декомпрессия этой кодовой последовательности с количеством циклов достаточна только для одного файла, если файлов больше, это будет невозможно, поэтому выберите более широкое поле и добавьте код, который автоматически дублирует количество циклов.
picos school
Anonse erotyczne wejherowo
Ogłoszenia erotyczne olx
Roksa grybow
Because all games in free games unblocked are currently unblocked, you might even utilize a smart device like a smartphone, iPad, or PC to play them at work or school.
This is a very great post and the way you express all your post details is too good. Thanks for sharing with us this useful post interior painting near me Raleigh NC
In addition, to test how removing unreachable code works, the widget will have an unused methodunused drywall contractors dallas tx
what are you waiting for snake games? You should click and challenge any players in the world.
There is nothing better than finding yourself a good game and playing at home on hot summer days. I recommend duck life to you.
I appreciate you sharing the facts and advice, and I will take them into consideration. The game traffic jam 3d is fun which you can try wherever you want.
A nagging sensation in the back of their heads compels them to come to a halt, but Riley is obligated to continue watching the tapes in amanda the adventurer
Articles with very interesting topics. 8 ball pool
All of the emoji characters are now accessible for you to copy and paste with ease (just copy them and then paste them into the editor of your choice).
Google Closure Compiler works well with modern stumble guys syntax, including classes. Using classes helps organize your code in a more structured and OOP-oriented manner.
Excellent piece! This is a fantastic site that I plan on revisiting numerous times throughout the year. I appreciate your informative blog. mini crossword
Кроме того, для проверки, как работает удаление недостижимого кода, в виджете будет присутствовать неиспользуемый метод unused sacramento ca drywall repair
This is a fantastic site that I plan on revisiting numerous slope
You have created a work that is very enjoyable to read, bringing enlightenment to every topic for us to acquire knowledge happy wheels. Thank you for sharing such information for us to read...
I thoroughly enjoyed your article play wordle; it was captivating and made my morning coffee even more delightful. Thank you for sharing such a high-quality piece.
Be able to create comparative themes with pleasure! Welcome here and you will discover what it should look like.먹튀신고
tiny fishing - Simple, pleasant and so good
This can certainly happen moto x3m
Very interesting article. This is my first time coming here fnaf. I found a lot of interesting things in your blog, especially the discussion therein. Thanks for the post! retro games
It gives me great pleasure to convey my sincere gratitude for the outstanding quality of the previously mentioned products. The writer has produced a remarkable and thought-provoking work that exhibits a strong command of language and the capacity to organize thoughts. papa's freezeria
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.