Заметки за 2012 год (страница 3)

Как git rebase помогает управлять коммитами

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

Но, нигде не упоминается об интерактивном режиме и его возможностях. В этом режиме можно переставлять коммиты местами, объединять и разделять их, менять комментарии у произвольного коммита. Всё это может понадобиться, если использовать подход « микрокоммитов ».

Комментарии к заметке: 1

Копирование файлов по SSH

Традиционным способом копирования файлов по SSH является команда scp.

scp *.js user@remote-host.com:~/folder/

Все файлы с расширением js из текущей папки будут скопированы на сервер remote-host.com в папку folder в домашней директории пользователя user.

Можно так же копировать папку вместе со всеми файлам и вложенными папками:

scp -r src user@remote-host.com:~/folder/

А теперь нетрадиционный способ:


tar -c src | ssh user@remote-host.com "cd ~/folder/ && tar -x"

Папка src архивируется утилитой tar . Затем этот архив передается на сервер по SSH, где выполняется команда cd с указанными параметрами и распаковывается полученный архив.

Пример чуть сложнее:


npm run build && \
DEPLOY_TARGET=$(date +%Y%m%d-%H%M%S) && \
tar -c build | \
ssh -t mista_k@slim.local \
  `cd /var/www && \
  mkdir -p $DEPLOY_TARGET && \
  tar -x -C $DEPLOY_TARGET --strip-components 1 -v && \
  ln -sfn $DEPLOY_TARGET build`

Комментарии к заметке: 4

Профилирование CSS и неиспользуемые селекторы

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

А что произойдет, если браузер никогда не встретит элемент с нужными характеристиками во время такого обхода? Чтобы ответить на этот вопрос я решил сделать несколько замеров скорости отрисовки достаточно сложной страницы (около 2500 элементов и глубиной 20 уровней). Страница содержала реальные и вполне типичные для проекта данные — таблица на сотню строк, свёрстанная блочными элементами.

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

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

Сначала я сделал замер с подключенными стилями темы.

Эксперимент с подключенными стилями темы jQuery UI

А затем повторил эксперимент без подключения этих стилей.

Эксперимент без стилей jQuery UI

По рейтингу затраченного времени на пересчёт стилей видно, что самыми «тяжёлыми» оказались каскады, для которых никогда не находятся подходящие элементы. На странице множество элементов span (1123, если быть точнее), но, ни один не имеет предка с классом ui-datepicker-next или ui-datepicker-prev.

Из этого конкретного эксперимента можно сделать вывод, что чем больше будет загружено CSS-правил, тем медленнее будет работать движок браузера на перерисовке страницы, даже если эти правила никогда не будет применены на странице.

Отсюда напрашивается ещё один вывод: объединение разношерстных стилей в один файл с большой вероятностью ухудшит производительность стадий reflow и repaint. Деградация будет не так заметна, если в стилях гарантировано не применяются каскады с селекторами по тегу.

Комментарии к заметке: 6

Подсветка области клика на iOS

Когда пользователь прикасается к ссылке или элементу, для которого указан обработчик клика, то Safari на iOS подсвечивает этот элемент.

Цвет этой подсветки задается с помощью CSS свойства -webkit-tap-highlight-color.

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

Предположим, что нас интересует только клик по элементу с классом item__add.


$(".list").on("click", ".item__add", function () { … });

Но подсветка будет активироваться у элемента с классом list , так как именно на него повешен обработчик события. Исправим это CSS свойством в селекторе .list.


.list {
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
Комментарии к заметке: 3

Конкурирующие асинхронные запросы

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


var concurrent = (function () {
    var concurrentRequests = {};
    return function (opts, cache) {
        // вместо jqXHR функция будет возвращать promise-объект
        var deferred = $.Deferred(), promise = deferred.promise();

        // сохраняем колбеки, если они есть
        promise.done(opts.success || $.noop);
        promise.fail(opts.error || $.noop);
        promise.always(opts.complete || $.noop);

        // удаляем колбеки из параметров,
        // так как cacheable не обрабатывает их
        delete opts.success;
        delete opts.error;
        delete opts.complete;

        // таймстемп запроса.
        // ответы с таймстемпом меньше текущего игнорируются
        var requestId = concurrentRequests[opts.url] = $.now();

        // кеширующий или обычный запрос
        (cache ? cacheable : $.ajax)(opts)
            .done(function () {
                if (concurrentRequests[opts.url] <= requestId) {
                    deferred.resolveWith(promise,
                        Array.prototype.slice.apply(arguments));
                }
            })
            .fail(function () {
                if (concurrentRequests[opts.url] <= requestId) {
                    deferred.rejectWith(promise,
                        Array.prototype.slice.apply(arguments));
                }
            });

        return promise;
    }
}());

В паре с функций cacheable получилась достаточно универсальная замена традиционной функции $.ajax.


$(".list").each(function () {
    var list = $(this);
    list.on("click", ".list__page", function () {
        concurent({
            url: "/list/",
            data: {page: $.tim($(this).text())},
            dataType: "html"
        }, true).done(function (markup) {
            list.html(markup);
        });
    });
});

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