Javascript.RU

Улучшаем сжимаемость Javascript-кода.

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/better-minification.

При сжатии javascript-кода минификатор делает две основные вещи.

  1. удаляет заведомо лишние символы: пробелы, комментарии и т.п.
  2. заменяет локальные переменные более короткими.

В статье рассматриваются минификаторы YUI Compressor и ShrinkSafe.
На момент написания это лучшие минификаторы javascript.

Есть несколько несложных приемов программирования, которые могут увеличить сжимаемость JS-кода.

Минификатор заменяет все локальные переменные на более короткие
(Также о сжатии в статье Сжатие Javascript и CSS).

Например, вот такой скрипт:

function flyToMoon(moon) {
  var spaceShip = new SpaceShip()
  spaceShip.fly(moon.getDistance())
}
</div>

После минификации станет:

function flyToMoon(A) {
  var B = new SpaceShip()
  B.fly(A.getDistance())
}

Заведомо локальные переменные moon, spaceShip могут быть безопасно заменены на более короткие A,B. Минификатор использует патченный открытый интерпретатор javascript, написанный на java: Rhino, он разбирает код, анализирует и собирает обратно с заменой, поэтому все делается корректно.

С другой стороны, название функции в этом скрипте - глобальная переменная, оно не сжимается, чтобы сохранить возможность обращения к функции.

По тем же причинам не сжимается вызов SpaceShip и методы fly, getDistance().

Итак, сделаем какой-нибудь более реальный скрипт и напустим на него YUI Compressor.

function SpaceShip(fuel) {
    
    this.fuel = fuel
    
    this.inflight = false
        
    this.showWarning = function(message) {
        var warningBox = document.createElement('div')
        with (warningBox) {
            innerHTML = message
            className = 'warningBox'
        }
        document.body.appendChild(warningBox)        
    }
    
    this.showInfo = function(message) {
        var messageBox = document.createElement('div')
        messageBox.innerHTML = message
        document.body.appendChild(messageBox)        
    }
    
    this.fly = function(distance) {
        if (distance<this.fuel) {
            this.showWarning("Мало топлива!")
        } else {            
            this.inflight = true
            this.showInfo("Взлетаем")
        }
    }
    
}

function flyToMoon() {
    var spaceShip = new SpaceShip()
    spaceShip.fly(1000)
}

flyToMoon()

К сожалению, в YUI Compressor нельзя отключить убивание переводов строки, поэтому получилось такое:

function SpaceShip(fuel){this.fuel=fuel;
this.inflight=false;this.showWarning=function(message){
var warningBox=document.createElement("div");
with(warningBox){innerHTML=message;
className="warningBox"
}document.body.appendChild(warningBox)
};this.showInfo=function(message){
var messageBox=document.createElement("div");
messageBox.innerHTML=message;
document.body.appendChild(messageBox)
};this.fly=function(distance){
if(distance<this.fuel){this.showWarning("Мало топлива!")
}else{this.inflight=true;
this.showInfo("Взлетаем")
}}}function flyToMoon(){var A=new SpaceShip();
A.fly(1000)};flyToMoon()

Если посмотреть внимательно - видно, что локальные переменные вообще не сжались внутри SpaceShip, а сжались только в функции flyToMoon.

ShrinkSafe замечательно сжимает все, что только может.

function SpaceShip(_1){
this.fuel=_1;
this.inflight=false;
this.showWarning=function(_3){
var _4=document.createElement("div");
with(_4){
innerHTML=_3
className="warningBox";
}
document.body.appendChild(_4);
};
this.showInfo=function(_5){
var _6=document.createElement("div");
_6.innerHTML=_5;
document.body.appendChild(_6);
};
this.fly=function(_7){
if(_7<this.fuel){
this.showWarning("Мало топлива!");
}else{
this.inflight=true;
this.showInfo("Взлетаем");
}
};
};
function flyToMoon(){
var _8=new SpaceShip();
_8.fly(1000);
};
flyToMoon();

Все локальные переменные заменены на более короткие _варианты.

Почему YUI не сжал, а ShrinkSafe справился?

Дело в конструкции with() { ... } в методе showWarning. Эти два компрессора по-разному к ней относятся.

ShrinkSafe игнорирует нелокальные названия переменных внутри with:

// Было
with(val) {
  prop = val
}
// Стало
with(_1) {
  prop = _1
}

К сожалению, в последней версии ShrinkSafe есть баг: если переменная prop объявлена локально, то она заменяется:

// Было
var prop
with(val) {
  prop = val
}
// Стало
var _1
with(_2) {
  _1 = _2
}

Например, если val = { prop : 5 }, то сжатая таким образом конструкция with сработает неверно из-за сжатия prop до _1.

Впрочем, никогда не слышал, чтобы кто-то на такой баг реально напоролся. Видимо, люди локальные переменные не объявляют одноименные со свойствами аргумента with, чтобы код понятнее был.

Внутри оператора with(obj) никогда нельзя точно сказать: будет ли переменная взята из obj или из внешней области видимости.

Поэтому никакие переменные внутри with сжимать нельзя.

А раз так - получается, что локальные переменные с именами, упомянутыми внутри with тоже сжимать нельзя.

YUI Compressor почему-то (почему? есть идеи?) пошел еще дальше: он не минифицирует вообще никаких локальных переменных даже в соседних функциях.

Может быть, это баг (версия 2.3.5), а может - фича, не знаю. Будут идеи - пишите в комментариях. Например, локальные переменные функции fly вполне можно было минифицировать.

Вывод:

YUI категорически не любит with.

ShrinkSafe любит, но с багофичей.

Если заменить функцию showWarning на вариант без with, то YUI сожмет код без проблем:

// вариант без with
this.showWarning = function(message) {
        var warningBox = document.createElement('div')
        warningBox.innerHTML = message
        warningBox.className = 'warningBox'        
        document.body.appendChild(warningBox)        
}

Результат сжатия YUI без with:

function SpaceShip(A){this.fuel=A;
this.inflight=false;this.showWarning=function(B){var C=document.createElement("div");
C.innerHTML=B;C.className="warningBox";
document.body.appendChild(C)
};this.showInfo=function(B){var C=document.createElement("div");
C.innerHTML=B;document.body.appendChild(C)
};this.fly=function(B){if(B<this.fuel){this.showWarning("Мало топлива!")
}else{this.inflight=true;
this.showInfo("Взлетаем")
}}}function flyToMoon(){var A=new SpaceShip();
A.fly(1000)}

В примере не сжались вызовы к объекту document.

Для того, чтобы сжатие сработало, надо заменить обращение к глобальной переменной document вызовом локальной функции.

Например, вот так:

function SpaceShip(fuel) {
    /* сокращенные локальные вызовы */
    var doc = document
    var createElement = function(str) {
        return doc.createElement(str)
    }
    var appendChild = function(elem) {
        doc.body.appendChild(elem)
    }

    this.fuel = fuel
    
    this.inflight = false
        
    this.showWarning = function(message) {
        var warningBox = createElement('div')
        warningBox.innerHTML = message
        warningBox.className = 'warningBox'        
        appendChild(warningBox)        
    }
    
    this.showInfo = function(message) {
        var messageBox = createElement('div')
        messageBox.innerHTML = message
        appendChild(messageBox)        
    }
    
    this.fly = function(distance) {
        if (distance<this.fuel) {
            this.showWarning("Мало топлива!")
        } else {            
            this.inflight = true
            this.showInfo("Взлетаем")
        }
    }    
}

Обращение к document осталось в одном месте, что тут же улучшает сжатие:

(Здесь и дальше для сжатия использован ShrinkSafe, т.к он оставляет переводы строки.
Результаты YUI - по сути, такие же)

function SpaceShip(_1){
var _2=document;
var _3=function(_4){
return _2.createElement(_4);
};
var _5=function(_6){
_2.body.appendChild(_6);
};
this.fuel=_1;
this.inflight=false;
this.showWarning=function(_7){
var _8=_3("div");
_8.innerHTML=_7;
_8.className="warningBox";
_5(_8);
};
this.showInfo=function(_9){
var _a=_3("div");
_a.innerHTML=_9;
_5(_a);
};
this.fly=function(_b){
if(_b<this.fuel){
this.showWarning("Мало топлива!");
}else{
this.inflight=true;
this.showInfo("Взлетаем");
}
};

Как правило, в интерфейсах достаточно много обращений к document, и все они длинные, поэтому этот подход может уменьшить сразу код эдак на 10-20%.

Функции объявлены через var, а не function:

var createElement = function(str) { // (1)
  return doc.createElement(str)
}
// а не
function createElement(str) {  // (2)
  return doc.createElement(str)
}

Это нужно для ShrinkSafe, который сжимает только определения (1). Для YUI - без разницы, как объявлять функцию, сожмет и так и так.

Существуют различные способы объявления объектов.
Один из них - фабрика объектов, когда для создания не используется оператор new.

Общая схема фабрики объектов:

function object() {
  var private = 1  // приватная переменная для будущего объекта

  return {   // создаем объект прямым объявлением в виде { ... }
    increment: function(arg) {  // открытое свойство объекта
        arg += private // доступ к приватной переменной
        return arg
    }
  }
}
// вызов не new object(), а просто
var obj = object()

Прелесть тут состоит в том, что приватные переменные являются локальными, и поэтому могут быть сжаты. Кроме того, убираются лишние this.

function SpaceShip(fuel) {
    var doc = document

    var createElement = function(str) {
        return doc.createElement(str)
    }
    var appendChild = function(elem) {
        doc.body.appendChild(elem)
    }
    
    var inflight = false    
    
    var showWarning = function(message) {
        var warningBox = createElement('div')
        warningBox.innerHTML = message
        warningBox.className = 'warningBox'        
        appendChild(warningBox)        
    }
    
    var showInfo = function(message) {
        var messageBox = createElement('div')
        messageBox.innerHTML = message
        appendChild(messageBox)        
    }
    
    return {
        fly: function(distance) {
            if (distance<this.fuel) {
                showWarning("Мало топлива!")
            } else {            
                inflight = true
                showInfo("Взлетаем")
            }
        }
    }
    
}

function flyToMoon() {
    var spaceShip = SpaceShip()
    spaceShip.fly(1000)
}
function SpaceShip(_1){
var _2=document;
var _3=function(_4){
return _2.createElement(_4);
};
var _5=function(_6){
_2.body.appendChild(_6);
};
var _7=false;
var _8=function(_9){
var _a=_3("div");
_a.innerHTML=_9;
_a.className="warningBox";
_5(_a);
};
var _b=function(_c){
var _d=_3("div");
_d.innerHTML=_c;
_5(_d);
};
return {fly:function(_e){
if(_e<this.fuel){
_8("Мало топлива!");
}else{
_7=true;
_b("Взлетаем");
}
}};
};
function flyToMoon(){
var _f=SpaceShip();
_f.fly(1000);
};
flyToMoon();

Максимально возможное использование локальных переменных, собственно, и улучшает минификацию. А некоторые подходы в этой статье - лишь иллюстрации.


Автор: sores (не зарегистрирован), дата: 20 июня, 2008 - 11:53
#permalink

ВОопщето вот лучший минимизатор!
http://dean.edwards.name/packer/


Автор: Илья Кантор, дата: 20 июня, 2008 - 12:36
#permalink

Это неправда.

packer не следует вообще использовать, если на сервере стоит mod_gzip/deflate/compress.


Автор: sunnybear (не зарегистрирован), дата: 23 июля, 2008 - 21:36
#permalink

Однозначно сказать нельзя. В общем случае, да. Но не всегда


Автор: Илья Кантор, дата: 23 июля, 2008 - 23:36
#permalink

Приведите, пожалуйста, хоть один пример скрипта, на котором результат packer + gzip весит меньше, чем просто gzip.


Автор: Гость (не зарегистрирован), дата: 25 января, 2009 - 19:32
#permalink
jQuery JavaScript Library v1.3:
-----------------
jquery.pack                                        js │   38058│
jquery.pack.js                                     gz │   18997│

*(gzip -9)


Автор: Гость (не зарегистрирован), дата: 25 января, 2009 - 19:36
#permalink
jquery.pack.js         │   38058
jquery.js.gz           │   34278
jquery.pack.js.gz      │   18997

Автор: Илья Кантор, дата: 27 февраля, 2009 - 09:45
#permalink

Дополнил статью по сжатию - смотрите в конец, там мои результаты по сжатию jQuery 1.3.2 с использованием php-packer 1.1, yui 2.4.2(он же - родной минифай) и gzip.

Да, действительно, gzip + packer могут работать вместе. Предполагаю, что это благодаря той части packer, которая реализует регэкспы. Регэкспы используют знание о структуре кода, которого нет у gzip.

Возможно, gzip + packer работали бы еще лучше вместе, если б из packer убрать псевдо-гзип и оставить только регэкспы.. Но тогда уже получится минифай вместо пакера.

Итого, лучше всех: yui + gzip.

P.S. Если еще есть что обсудить - лучше там, здесь все же статья по оптимизации для сжатия, а не по самому сжатию.


Автор: Гость (не зарегистрирован), дата: 20 июня, 2008 - 14:17
#permalink

В Опере страничка отображается неправильно


Автор: Илья Кантор, дата: 20 июня, 2008 - 23:43
#permalink

Да, совсем забыл об этом

Оказались непротестаны изменения верстки в опере. Поправил.


Автор: sunnybear (не зарегистрирован), дата: 23 июля, 2008 - 21:37
#permalink

К сожалению, все эти фишки актуальны только при отсутствии сжатия. Само сжатия уменьшает код раз в 5, поэтому дальнейшая оптимизация зачастую бессмысленна.


Автор: Илья Кантор, дата: 23 июля, 2008 - 23:36
#permalink

Зачастую сжатие в 5 раз еще не означает сжатие до нуля


Автор: Zebooka (не зарегистрирован), дата: 29 сентября, 2008 - 11:00
#permalink

Собственно не верное утверждение.
Ибо эти фишки можно использовать как обфускатор. Для запутывания кода.


Автор: Гость (не зарегистрирован), дата: 21 сентября, 2008 - 13:13
#permalink

А может лучше просто самому писать короткий код?


Автор: миркус (не зарегистрирован), дата: 26 января, 2009 - 16:41
#permalink

а после тебя трынь трава?
другой разработчик будет сидеть голову ломать?

имхо,писать лучше читабельным кодом.
с комментами.

а уже выкладывая проект в сеть,
шаманить над оптимизацией и т.д...
-
выкладывая и исходный вариант кода с доступом разработчику.


Автор: imsha, дата: 7 декабря, 2011 - 10:53
#permalink

Коммент неудачно написал уровнем ниже....

А сам через месяц когда вернешься поправить баг и сразу в ступор.
Мы на работе договорились даже об определенной семантике названия объектов и т.п. Пусть даже они будут длинными. Зато поддерживать удобнее. При факте - что вероятнее всего другой разработчик будет этим заниматься.

ТС, за статью спасибо. Буквально на днях скрещивал Tortoise Svn с батниками и YUI Compressor. Теперь есть о чем подумать и как все это дело допилить еще лучше.


Автор: Dima (не зарегистрирован), дата: 28 октября, 2008 - 22:32
#permalink

Для конкретного кода подходят разные типы сжатия кода.
Вообще, понравилась статья, узнал кое-что новое.


Автор: Мариана (не зарегистрирован), дата: 13 ноября, 2008 - 15:55
#permalink

Зачастую сжатие в 5 раз еще не означает сжатие до нуля


Автор: Нина (не зарегистрирован), дата: 22 ноября, 2008 - 13:33
#permalink

а для чего вообще сжимать, зачем такие сложности?


Автор: Илья Кантор, дата: 22 ноября, 2008 - 20:21
#permalink

Чтобы быстрее загружалось


Автор: gps (не зарегистрирован), дата: 13 августа, 2009 - 16:42
#permalink

Спасиб отличный сайт...


Автор: Гость (не зарегистрирован), дата: 3 сентября, 2009 - 13:51
#permalink

Отличный пакер!
Сделал простую обертку для запуска этого crunchy из командной строки:

<package>
<job>
<script language="javascript">
window = {};
var WS = WScript, oFSO = new ActiveXObject("Scripting.FileSystemObject"),
function alert(arg){
    WS.echo(arg)
};
function readFile(fileName) {
    var stream = oFSO.OpenTextFile(fileName),
        text = stream.ReadAll();
    stream.Close()
    return text
};

function createAndWriteFile(fileName, text) {
    var streem = oFSO.CreateTextFile(fileName);
    streem.Write(text);
};

function pack(sourceText) {
    sourceText = sourceText.replace(/\r*\n/g, "\n").replace(/\r/g, "\n");
    try {
        return Crunchy.crunch(sourceText);
    } catch (error) {

    }
};

</script>
<script src="web-crunchy.js" language="javascript"></script>
<script language="javascript">

var args = WS.arguments;
if( args.length < 1 ) WS.Quit(1);

var inputFileName = args.item(0);
var outputFileName = args.length < 2 ?
    inputFileName.replace(/(\.js$)|$/, "(crunchy-compressed).js") :
    args.item(1);

createAndWriteFile(outputFileName, pack(readFile(inputFileName)));

</script>
</job>
</package>

Автор: Гость (не зарегистрирован), дата: 4 октября, 2018 - 12:54
#permalink

Защитить код можно достаточно просто, помогут статьи.


Автор: Bob Williams (не зарегистрирован), дата: 22 октября, 2019 - 10:34
#permalink

Очень Помогли спасибо вам огромная.

Gun Mayhem 2


Автор: osama shk (не зарегистрирован), дата: 28 января, 2020 - 18:46
#permalink

Interesting post. I Have Been wondering about this issue, so thanks for posting. Pretty cool post.It 's really very nice and Useful post.Thanks
click this site


Автор: qagaty (не зарегистрирован), дата: 31 января, 2020 - 14:31
#permalink

I’ve read some good stuff here. Definitely worth bookmarking for revisiting. I surprise how much effort you put to create such a great informative website.


Автор: osama shk (не зарегистрирован), дата: 1 февраля, 2020 - 12:20
#permalink

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.
bitcoin news


Автор: osama kji (не зарегистрирован), дата: 2 февраля, 2020 - 18:25
#permalink

That appears to be excellent however i am still not too sure that I like it. At any rate will look far more into it and decide personally!
ataque de pánico


Автор: sond (не зарегистрирован), дата: 10 февраля, 2020 - 22:51
#permalink

I have a hard time describing my thoughts on content, but I really felt I should here. Your article is really great. I like the way you wrote this information.
Digital Marketing Agency


Автор: osama shk (не зарегистрирован), дата: 12 февраля, 2020 - 18:36
#permalink

Great articles and great layout. Your blog post deserves all of the positive feedback it’s been getting.
https://champagne-pools.com


Автор: osama shk (не зарегистрирован), дата: 15 февраля, 2020 - 14:27
#permalink

I am very happy to discover your post as it will become on top in my collection of favorite blogs to visit.
rico chandra kusuma


Автор: osama shk (не зарегистрирован), дата: 15 февраля, 2020 - 16:52
#permalink

Just admiring your work and wondering how you managed this blog so well. It’s so remarkable that I can't afford to not go through this valuable information whenever I surf the internet!
go here


Автор: osama shk (не зарегистрирован), дата: 15 февраля, 2020 - 18:10
#permalink

If you set out to make me think today; mission accomplished! I really like your writing style and how you express your ideas. Thank you.
https://worldsbestdogfoods.org/


Автор: osama shk (не зарегистрирован), дата: 15 февраля, 2020 - 19:00
#permalink

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post.
divorce lawyers colorado springs


Автор: osama shk (не зарегистрирован), дата: 16 февраля, 2020 - 20:15
#permalink

I like this post,And I guess that they having fun to read this post,they shall take a good site to make a information,thanks for sharing it to me.
https://sportstv.io/en/watch-live/all-sports/upcoming


Автор: osama shk (не зарегистрирован), дата: 17 февраля, 2020 - 17:14
#permalink

I have read your blog it is very helpful for me. I want to say thanks to you. I have bookmark your site for future updates.
read the article


Автор: osama shk (не зарегистрирован), дата: 17 февраля, 2020 - 18:10
#permalink

Great job for publishing such a beneficial web site. Your web log isn’t only useful but it is additionally really creative too. There tend to be not many people who can certainly write not so simple posts that artistically. Continue the nice writing
learn here


Автор: osama shk (не зарегистрирован), дата: 17 февраля, 2020 - 18:51
#permalink

Thank you so much for sharing this great blog.Very inspiring and helpful too.Hope you continue to share more of your ideas.I will definitely love to read.
look at this


Автор: osama shk (не зарегистрирован), дата: 17 февраля, 2020 - 19:49
#permalink

Thank you for some other informative blog. Where else could I get that type of information written in such an ideal means? I have a mission that I’m just now working on, and I have been at the look out for such information.
TheFancyVoyager


Автор: osama shk (не зарегистрирован), дата: 19 февраля, 2020 - 15:03
#permalink

If you set out to make me think today; mission accomplished! I really like your writing style and how you express your ideas. Thank you.
bioharzard cleanup


Автор: osama shk (не зарегистрирован), дата: 23 февраля, 2020 - 17:26
#permalink

I just found this blog and have high hopes for it to continue. Keep up the great work, its hard to find good ones. I have added to my favorites. Thank You.
https://arkserverhosting.co.uk


Автор: Гость (не зарегистрирован), дата: 24 февраля, 2020 - 13:13
#permalink

I think that thanks for the valuabe information and insights you have so provided here.
Cardiovascular disease


Автор: osama shk (не зарегистрирован), дата: 24 февраля, 2020 - 19:15
#permalink

Interesting post. I Have Been wondering about this issue, so thanks for posting. Pretty cool post.It 's really very nice and Useful post.Thanks
https://trulylovelykitchen.com


Автор: osama shk (не зарегистрирован), дата: 25 февраля, 2020 - 12:39
#permalink

Great info! I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have.
dji mavic air


Автор: john bond (не зарегистрирован), дата: 25 февраля, 2020 - 14:31
#permalink

You make so many great points here that I read your article a couple of times. Your views are in accordance with my own for the most part. This is great content for your readers.
crime scene cleanup


Автор: osama shk (не зарегистрирован), дата: 25 февраля, 2020 - 16:16
#permalink

Superbly written article, if only all bloggers offered the same content as you, the internet would be a far better place..
go right here


Автор: johnb (не зарегистрирован), дата: 25 февраля, 2020 - 19:26
#permalink

Hi! Thanks for the great information you have provided! You have touched on crucuial points!
TLK


Автор: osama shk (не зарегистрирован), дата: 25 февраля, 2020 - 20:15
#permalink

I found this is an informative and interesting post so i think so it is very useful and knowledgeable. I would like to thank you for the efforts you have made in writing this article.
hair dry machine


Автор: johnsss (не зарегистрирован), дата: 26 февраля, 2020 - 15:45
#permalink

I was surfing net and fortunately came across this site and found very interesting stuff here. Its really fun to read. I enjoyed a lot. Thanks for sharing this wonderful information.
Boiler installation


Автор: osama shk (не зарегистрирован), дата: 27 февраля, 2020 - 16:43
#permalink

I am very much pleased with the contents you have mentioned. I wanted to thank you for this great article.
psicologos en Madrid para adolescentes


Автор: johnb6 (не зарегистрирован), дата: 29 февраля, 2020 - 12:07
#permalink

This is a great inspiring article.I am pretty much pleased with your good work.You put really very helpful information. Keep it up. Keep blogging. Looking to reading your next post.
Orange County Air Conditioning Home Service


Автор: johnb6 (не зарегистрирован), дата: 29 февраля, 2020 - 17:19
#permalink

Thank you for another great article. Where else could anyone get that kind of information in such a perfect way of writing? I have a presentation next week, and I am on the look for such information.
hair dry machine


Автор: Гость (не зарегистрирован), дата: 1 марта, 2020 - 15:45
#permalink

Its a great pleasure reading your post.Its full of information I am looking for and I love to post a comment that "The content of your post is awesome" Great work.
psicologos para adolescentes en Madrid


Автор: osama shk (не зарегистрирован), дата: 18 марта, 2020 - 13:18
#permalink

Thank you for such a well written article. It’s full of insightful information and entertaining descriptions. Your point of view is the best among many.
マリッジリング


Автор: osama shk (не зарегистрирован), дата: 19 марта, 2020 - 19:17
#permalink

Thanks for sharing nice information with us. i like your post and all you share with us is uptodate and quite informative, i would like to bookmark the page so i can come here again to read you, as you have done a wonderful job.
婚約指輪 福岡


Автор: calywico calywico (не зарегистрирован), дата: 21 марта, 2020 - 16:25
#permalink

Thank you so much for sharing this great blog.Very inspiring and helpful too.Hope you continue to share more of your ideas.I will definitely love to read.
search for company in cyprus


Автор: osama shk (не зарегистрирован), дата: 21 марта, 2020 - 22:13
#permalink

Great content material and great layout. Your website deserves all of the positive feedback it’s been getting.
エンゲージリング


Автор: osama shk (не зарегистрирован), дата: 22 марта, 2020 - 22:30
#permalink

I admit, I have not been on this web page in a long time... however it was another joy to see It is such an important topic and ignored by so many, even professionals. professionals. I thank you to help making people more aware of possible issues.
結婚指輪 手作り


Автор: feroz (не зарегистрирован), дата: 23 марта, 2020 - 12:43
#permalink

Thanks for this great post, i find it very interesting and very well thought out and put together. I look forward to reading your work in the future.
temp-mail


Автор: osama shk (не зарегистрирован), дата: 23 марта, 2020 - 23:38
#permalink

I have been checking out a few of your stories and i can state pretty good stuff. I will definitely bookmark your blog
婚約指輪 福岡


Автор: osama shk (не зарегистрирован), дата: 24 марта, 2020 - 16:02
#permalink

I found that site very usefull and this survey is very cirious, I ' ve never seen a blog that demand a survey for this actions, very curious...
エンゲージリング


Автор: osama shk (не зарегистрирован), дата: 24 марта, 2020 - 22:29
#permalink

Awesome article! I want people to know just how good this information is in your article. It’s interesting, compelling content. Your views are much like my own concerning this subject.
ハワイアンジュエリー


Автор: osama shk (не зарегистрирован), дата: 25 марта, 2020 - 21:15
#permalink

Superbly written article, if only all bloggers offered the same content as you, the internet would be a far better place..
婚約指輪 猫


Автор: osama shk (не зарегистрирован), дата: 25 марта, 2020 - 23:00
#permalink

Thanks for the nice blog. It was very useful for me. I'm happy I found this blog. Thank you for sharing with us,I too always learn something new from your post.
結婚指輪 手作り


Автор: osama shk (не зарегистрирован), дата: 25 марта, 2020 - 23:48
#permalink

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading. Nice blog, I will keep visiting this blog very often.
婚約指輪 福岡


Автор: osama shk (не зарегистрирован), дата: 28 марта, 2020 - 00:17
#permalink

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post.
ハワイアンジュエリー 結婚指輪


Автор: osama shk (не зарегистрирован), дата: 2 апреля, 2020 - 12:43
#permalink

Excellent .. Amazing .. I’ll bookmark your blog and take the feeds also…I’m happy to find so many useful info here in the post, we need work out more techniques in this regard, thanks for sharing.
barzo otslabvane


Автор: osama shk (не зарегистрирован), дата: 20 апреля, 2020 - 14:59
#permalink

Thank you for such a well written article. It’s full of insightful information and entertaining descriptions. Your point of view is the best among many.
bemer mats


Автор: osama shk (не зарегистрирован), дата: 20 апреля, 2020 - 22:13
#permalink

An fascinating discussion is value comment. I think that it is best to write extra on this matter, it won’t be a taboo topic however generally people are not enough to talk on such topics. To the next. Cheers
pulsed magnetic field therapy


Автор: osama shk (не зарегистрирован), дата: 10 мая, 2020 - 21:06
#permalink

i am for the first time here. I found this board and I in finding It truly helpful & it helped me out a lot. I hope to present something back and help others such as you helped me.
free classified ads


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
8 + 9 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum