08.04.2009

Дилемма о загрузке JS-файлов

С одной стороны, конечно, хочется накладывать JS сразу по мере загрузки HTML. Иными словами, хорошо бы делать инициализацию JS-кода компонента сразу после загрузки HTML-кода компонента:

<div id="something">
    ...
</div>
<script>
    Something.init();
</script>

Понятно зачем — чтобы свести к минимуму задержку между двумя событиями: 1) HTML компонента отобразился и 2) JS компонента загрузился и инициализировался.

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

Разумеется, для этого нужно грузить JS-код компонента вперед HTML-кода (обычно это делают в <head>).

***

С другой стороны, следуя рекомендациям ведущих специалистов по борьбе с тормознутостью сайтов, хочется вынести загрузку всех JS-файлов в конец страницы (перед закрывающим тегом <body>).

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

Однако, минус очевиден — увеличивается задержка между рассмотренными выше событиями 1) и 2). То есть мы получаем, что пользователь дольше видит HTML с еще не наложенным яваскриптом.

***

Что делать? Я думаю, что правильный путь — это все-таки вынести загрузку всех JS-файлов в конец страницы, при этом в <head> грузить один маленький легковесный скрипт, который при попытке пользователя взаимодействовать с компонентом при еще не наложенном JS, будет сигнализировать ему, что, мол, все окей, подожди чуть-чуть, JS грузится и скоро наступит счастье.

Вот и Мэтт Снайдер похожим путем идет. А как вы решаете эту дилемму?

05.04.2009

JSLint

Валидировали, валидировали, да не вывалидировали.

Думаю, многие пробовали программу JSLint — валидатор для проверки корректности JavaScript-кода. Однако блиц-опрос знакомых разработчиков показал, что почти все пользуются им лишь изредка, и едва ли кто задумывался о том, чтобы сделать JSLint неотъемлемой частью процесса разработки.

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

Главное — не перегибать палку

Не стоит принимать отчет JSLint как истину в последней инстанции и сразу бросаться править код. Это всего лишь рекомендация, поэтому нужно включить у себя в голове thinking mode и по каждой ошибке в отчете решить самому — согласиться с JSLint или нет. Благодаря тому, что у JSLint есть множество опций, позволяющих указать какие ошибки искать, а какие игнорировать, этот инструмент можно легко настроить на свой вкус.

Варианты использования

1. Самый простой — пойти на сайт JSLint и скопипейстить свой код в форму валидации.

2. Виджеты JSLint Widget, JSLint Multi widget, JSLint Dashboard widget for Mac OS X.

Можно драгндропнуть JS-файл или целую папку в окошко виджета, и получить отчет JSLint. В настройках виджета есть полный комплект опций JSLint.

JSLint Widget

Чем больше объем JS-кода, тем больше хочется интеграции со средой разработки (IDE). Также для крупных проектов желательно сделать валидацию рутинной операцией, выполняющейся автоматически, например, на этапе сборки и упаковки JS-кода.

3. В Aptana есть встроенный JSLint, который изначально выключен. Включить можно в настройках: Preferences → Aptana → Editors → JavaScript → Validation. После этого код будет валидироваться по мере того, как вы его печатаете.

JSLint в Аптане

К сожалению, у JSLint в Аптане нет опций.

4. Плагин к Eclipse. В начале этого года компания RockstarApps выпустила JSLint Eclipse Plugin. Опции все есть, но нет возможности указать predefined global variables, что, конечно, обломно.

5. Rhino и Windows Script Host. На одном из проектов мы используем Rhino для запуска JSLint. Написали скрипт, который обходит все проектные JS-файлы, для каждого из них вызывает JSLint и формирует общий отчет — очень удобно! Пожалуй, надо будет написать отдельный пост про это :-)

JSLint продолжает развиваться. Следить за обновлениями можно в группе JSLint, куда часто пишет сам Крокфорд, автор JSLint.

А вы валидируете свой JavaScript-код?

15.03.2009

Электропочта

Инбокс

Для меня инбокс — это фактически туду-лист. Пока я не решил затронутую в письме проблему, письмо сидит в инбоксе. Как только по письму все сделано, оно немедленно отправляется в папку (или в Gmail навешивается метка и архивируется). Я часто сам себе пишу письма чтобы что-то не забыть, потому что знаю — если есть в инбоксе, то задача не промандится. Вообще не понимаю, как живут и работают люди, у которых все письма хранятся в инбоксе.

Фильтры

У меня настроено множество фильтров, с помощью которых все второстепенные, не имеющие непосредственного отношения к работе, письма минуют инбокс и расфасовываются по папкам, где они ждут, когда для них появится свободная минута. Прежде всего, это всевозможные рассылки и уведомления.

Периодичность проверки почты

Часто почта отвлекает и мешает плодотворной работе. Особенно, когда приходит новое письмо — так и тянет пойти посмотреть что же там пришло. Поэтому я выставляю достаточно большой интервал проверки новых писем, минимум — 30 минут. А когда требуется полное погружение в решение задачи или я чувствую, что работа спорится и не хочу отвлекаться, то вообще вырубаю почту.

Еще есть обратная болезнь — постоянно заходить в почту и нажимать на кнопку «Доставить почту». Эта зараза нападает, когда не охота что-то делать, и ищешь повод хоть немного отложить решение насущной проблемы. Лекарство — воспитывать силу воли.

Черновики

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

--

А у вас какие приемы работы с почтой для повышения собственной эффективности?

Передача параметров из HTML в JavaScript

Часто при инициализации JS-компонента нужно найти определенный DOM-элемент с которым компонент будет работать, а также достать из HTML параметры (настройки). О способах хранения и передачи в JS этих параметров я и хотел бы поговорить.

Раньше я решал эту задачу так: простые параметры передавал через классы, сложные — через дополнительные (не всегда валидные) атрибуты или дочерние элементы.

Предположим, у нас есть DOM-элемент:

<span id="test">тест</span>

При клике на этот элемент мы хотим показывать некий попап. Для показа попапа нужно задать следующие параметры: ширина, высота, таскаемость попапа и текст. Раньше я написал бы примерно следующее:

<span id="test" class="width_250 height_150 draggable"><span class="text">Трам-парам!</span>тест</span>

Потом я бы долго и муторно получал значения этих параметров путем выпарсивания их из классов и доставания из дочерних элементов.

Так бы и мучился дальше, если бы мой коллега Дима Филатов не подсказал гораздо более элегантное решение — прописать атрибут onclick в котором возвращать объект с настройками.

<span id="test" onclick="return {width: 250, height: 150, draggable: true, text: 'Трам-парам!'};">тест</span>

Как достать этот объект:

var element = document.getElementById('test');

// Забираем параметры
var options = element.onclick instanceof Function ? element.onclick() : {};

// Заметаем следы - обнуляем onclick
element.onclick = null;
element.removeAttribute('onclick');

// Навешиваем обработчик onclick для показа попапа
element.onclick = function () {
    showPopup(options);
};

По сути, для передачи настроек используется формат JSON в котором есть шесть типов значений: объект, массив, строка, число, булевское значение и null. Используя эти типы, можно передавать довольно сложную структуру данных, немыслимую для передачи через классы.

По-моему, очень круто. Блин, почему я сам не додумался до этого? :)

21.02.2009

Особенности верстки Gmail

Изучал на досуге верстку Gmail, и хочу поделиться с вами некоторыми наблюдениями.

1. Названия классов

Первое, что бросается в глаза, это нечеловеческие названия классов у элементов, например, xN0XZb или z1IiMc. Думаю, при выкладке в продакшн по названиям классов проходится обфускатор и скукоживает их до минимальной длины обеспечивающей уникальность.

2. Несемантическая верстка

Например, список папок сделан не ul>li, а дивчиками (адепты семантической верстки содрогнулись от ужаса). Однако, учитывая что все генерится яваскриптом, не вижу в этом большой проблемы.

3. Спрайт с фоном

Картинка со всеми иконками содержит фиолетово-голубой паттерн-бэкграунд.

Очевидно, сделано это для того, чтобы сразу заметить съехавшее на пиксел позиционирование иконки. Такая самотестирующаяся верстка получается. Круто, но я бы не решился отдавать в продакшн такую картинку. Мало ли что :)

4. Скругленные уголки

Думаю, в какой-то момент (вероятно, когда делали Themes) чуваки заманались вырезать эти уголки и сделали сервис, который генерит картинки на лету.

http://mail.google.com/mail/rc?a=af&c=c3d9ff&w=4&h=4
http://mail.google.com/mail/rc?a=af&c=black&w=32&h=16

Параметры: c — цвет в RGB или словом, w — ширина (от 1 до 64), h — высота (от 1 до 64). Что означает параметр a=af я не осилил.

Smart folks, those Google people :)

16.02.2009

Пока, Студия! Привет, Яндекс!

Сегодня был мой первый рабочий день в Яндексе.

Некоторое время назад я принял непростое решение покинуть Студию Лебедева. Мне нравилось в Студии. Можно сказать, это был мой второй дом. Однако, после почти 7 лет настала пора двигаться дальше.

Cпасибо Студии за все, что между нами было. Мне будет вас не хватать. Удачи!

14.02.2009

JavaScript!

Не перестаю удивляться сложности задач, которые можно решить с помощью JavaScript.

Один чувак написал распознавалку капчей сайта Megaupload. Джон Ресиг разобрал как это сделано.

Другой чувак заебошил карту мира на канвасе.

(Ну не говоря уже про Gmail, Google Reader и Google Docs.)

29.12.2008

JS: image.onload

Делал прелоадилку картинок и столкнулся с проблемой — в Опере у картинки иногда не срабатывал обработчик события onload.

Оказалось, проблема была в том, что я сначала задавал src и потом навешивал обработчик onload, а нужно делать наоборот. Причина проста: если картинка находится в кэше, то в Опере после задания src она загружается мгновенно, и событие onload срабатывает еще до того, как мы навесили обработчик onload.

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

Правильный код:

var image = document.createElement('img');
image.onload = function () {
    // вызывается всегда
    alert('image loaded');
};
image.src = 'test.jpg';

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

11.11.2008

Книги по JavaScript

За последние пару лет появилось много хороших книг по яваскрипту, что не может не радовать. Еще совсем недавно можно было посоветовать только «наименее плохую» книгу (Флэнагана). Сегодня же я могу порекомендовать вам три отличные книги.

John Resig
Pro JavaScript Techniques
Книга недавно вышла на русском языке

Джон Ресиг (JavaScript-евангелист в Mozilla Corporation и автор библиотеки jQuery) в своей книге рассказывает об объектно-ориентированном JavaScript, написании кода для повторного использования, тестировании и отладке, DOM, Events, Ajax.

К сожалению, в книге невероятно много опечаток, в том числе в примерах кода, что особенно неприятно. Также не понравилось, что иногда вместо подробного объяснения какой-либо темы, Ресиг приводит ссылки на статьи в интернете (на того же Крокфорда) где эта тема раскрыта. Я люблю уютно устроиться долгим зимним вечером в обнимку с книгой, и хочу чтобы книга была самодостаточна, чтобы не нужно было ползти за ноутбуком.

Оценка: 4

Не смотря на эти недостатки, я собираюсь заказать следующую книгу Ресига — Secrets of the JavaScript Ninja, выход которой запланирован на конец 2008 года. Оглавление выглядит впечатляюще и многообещающе.

Douglas Crockford
JavaScript: The Good Parts

Дуглас Крокфорд (главный по JavaScript в Yahoo!) хорошо известен как один из самых крутых специалистов по JavaScript. Дуглас — автор формата обмена данными JSON и сервиса по проверке корректности кода JSLint. Надо сказать, что его мегамощные лекции и статьи меня реально торкнули, поэтому его книгу я ждал с особым нетерпением.

Книга невелика по объему (всего 145 страниц), но насыщена информацией. Крокфорд пишет просто и понятно, без многословных и замысловатых выражений. Я не всегда стопроцентно с ним согласен, тем не менее, его аргументы весьма разумны, а его мнение стоит того, чтобы к нему прислушаться.

Что мне особенно понравилось в книге Крокфорда (а также в JSLint) — это внимание к стилю написания кода, как сделать код максимально ясным, кратким, однозначным, как уменьшить шанс возникновения ошибок.

Оценка: 5, must read

Ross Harmes, Dustin Diaz
Pro JavaScript Design Patterns

Супермегаохуенная книга о применении паттернов проектирования в JavaScript. Я давно мечтал прочитать такую. Организация кода, уменьшение зависимостей компонентов, как сделать код более гибким — вот главные темы книги.

Очень понравилось как авторы четко расставляют все по полочкам — для каждого паттерна приведены за и против его использования, какой выигрыш паттерн может дать, и в чем при этом можно потерять.

Оценка: 5+, must read

01.11.2008

Типовой лейаут страницы

Особенности:

  • Standards mode
  • Минимальная и максимальная ширина
  • При растяжении больше максимальной ширины макет центрируется
  • Футер всегда прибит к низу страницы

Тестовая страница

Простой пример использования

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>Sample layout</title>
        <link rel="stylesheet" type="text/css" href="main.css"/>
        <!--[if lte IE 6]><link rel="stylesheet" type="text/css" href="main-ie6.css"/><![endif]-->
    </head>
    <body>
        <div id="outer">
            <div id="header">header</div>
            <div id="content">content</div>
        </div>
        <div id="footer">footer</div>
    </body>
</html>

main.css

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}

body {
    color: #000;
    background-color: #fff;
    font-family: Arial, sans-serif;
    font-size: 0.8em;
    line-height: 1.4;
    text-align: center;
}

#outer {
    min-height: 100%;
}

#outer,
#footer {
    min-width: 700px;
    max-width: 1400px;
    margin: auto; /* center it */
    text-align: left;
}

#header {
    background-color: #66cc66;
}

#content {
    padding-bottom: 3.2em;
}

#footer {
    height: 2.6em;
    margin-top: -2.6em;
    background-color: #ff8080;
}

main-ie6.css

#outer {
    height: 100%;
}

#outer,
#footer {
    width: expression(document.documentElement.clientWidth < 700 ? '700px' : document.documentElement.clientWidth < 1400 ? '100%' : '1400px');
}