Компания
31,00
рейтинг
2 июня 2010 в 12:46

Разное → Как создавалась Айчиталка. Часть 1: движок

Совсем недавно мы выпустили в свет первую бета-версию нашей онлайн-читалки, с которой можно ознакомиться, почитав книгу Михаила Лермонтова «Герой нашего времени». Эта читалка — результат почти семимесячной работы, пять из которых ушло только на разработку движка. Казалось бы, в интернете уже есть бесплатные и открытые JavaScript-движки для чтения электронных книг и такой долгий срок может вызвать сомнения в профпригодности разработчика (то есть меня). Но есть одно большое и жирное «НО». Мы поставили перед собой слишком амбициозную и трудновыполнимую задачу: мы хотели использовать один и тот же движок на разных устройствах, в том числе маломощных, таких как айфон или электронная читалка.

В чём же заключается трудновыполнимость задачи? В первую очередь — в очень низкой скорости работы веб-приложений на айфоне. Например, мобильный Сафари по моим прикидкам работает раз в 100 медленнее своего десктопного собрата. Если на декстопе одна и та же операция выполняется 10 мс и совершенно незаметна для пользователя, то на айфоне она может выполняться больше секунды. Для сравнения: первая версия движка разбивала небольшую главу на страницы примерно за 15 секунд. Сейчас, спустя полгода, он делает то же самое менее, чем за секунду и вполне сносно работает в нашем приложении booq.

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



Задача


Для начала стоит объяснить, почему мы выбрали именно веб-технологии в качестве основы для читалки. Во-первых, это их распространённость. Сейчас довольно сложно найти устройство, которое не имеет встроенного браузера. Телефоны, компьютеры, нетбуки, планшеты, электронные книги – все они способны прочитать HTML, украсить его с помощью CSS и оживить через JavaScript. Имея один и тот же движок, мы можем легко создавать приложения для различных платформ и устройств. Во-вторых, ни один «классический» движок читалки не способен отобразить то, что может веб-браузер. Таблицы, векторная графика, аудио/видео контент, интерактивные элементы – всё это давно и успешно работает в браузерах. Представьте, что вы читаете научную книгу и тут же видите видеоролик, демонстрирующий описываемый процесс. Ну или читаете детектив, в котором нужно пройти паззл, чтобы открыть следующую главу :). Возможности ограничены только фантазией и умениями разработчика.

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

  • быть кроссбраузерным и кроссплатформенным;
  • иметь модульную структуру, чтобы легче было создавать версии под различные устройства;
  • поддерживать два режима чтения: постраничный и с прокруткой (как обычная веб-страница), а также быстро переключаться между ними;
  • обрабатывать главы объёмом 1 МБ+ (для сравнения: первый том «Войны и мира» Толстого весит 1,2 МБ);
  • иметь гибкие настройки внешнего вида (по сути, ограничены возможностями CSS).


В качестве тестовой площадки использовался айфон 2G с прошивкой 3.1 и глава из книги Ивана Миронова «Замурованные» весом 500 КБ. Такая большая глава скорее исключение, чем правило, однако задаёт хорошую планку по производительности, ниже которой не стоит опускаться.

Итак, приступим к оптимизации.

Объём JS-кода


Сразу хочу огорчить любителей наставить кучу фрэймворков на страницу и обвешать их плагинами, чтобы решить простые задачи вроде перетаскивания блоков или выбора элементов по CSS-селектору: объём JS-кода на странице имеет огромное значение, по крайней мере для мобильного Safari. Например, парсинг и инициализация популярного jQuery занимает 1400 мс для оригинальной, не сжатой версии (155 КБ) и 1200 мс для сжатой (76 КБ). Несмотря на то, что сжатая версия в 2 раза меньше оригинала, по функциональности они идентичны: отсюда такая «небольшая» разница в скорости парсинга. То есть на скорость влияет не длина названий переменных, а количество функций, объектов, методов и так далее. Для сравнения: на десктопе парсинг занимает порядка 30 мс.

Идеальный вариант: держать весь JS-код в самом низу страницы и вообще отказаться от фрэймворков. Так как сам по себе WebKit поддерживает много чего, я вынес стандартные DOM-операции (добавление событий, поиск элементов по селектору и т.д.) в виде отдельного дополнительного модуля, а для десктоп-версии переопределил этот слой, чтобы вызовы транслировались в jQuery.

Парсинг HTML


Сама читалка ориентирована на формат ePub, в котором каждая глава книги представлена отдельным документом в формате XHTML. Главу нужно каким-то образом передать в JavaScript, чтобы он её распарсил, разбил на страницы и начал показывать.

Тут стоит сказать пару слов о принципе вывода контента на экран. Напомню, что движок должен поддерживать два режима чтения: постраничный и «портянкой». Поэтому я решил весь контент обрамить в две обёртки: первая является своеобразным «окном», а вторая смещает контент вверх-вниз. Подобрав правильные размеры окна и смещения контента, можно создать иллюзию разбитой на страницы главы:



Так как мне в любом случае нужно всё содержимое главы, а для расчётов размеров страниц мне нужны полноценные DOM-элементы, я решил вывести главу прямо в HTML:

<div id="window">
  <div id="content">
    <p>В департаменте… но лучше не называть, в каком департаменте…</p>
  </div>
</div>


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

<div id="window">
  <div id="content" style="display:none">
    <p>В департаменте… но лучше не называть, в каком департаменте…</p>
  </div>
</div>


На этот раз парсинг страницы занимал 800 мс, что очень даже неплохо: ускорил почти в 10 раз. А так как у айфона довольно маленький экран, достаточно было достать из дерева несколько первых элементов и показать их, чтобы пользователь мог начать читать, пока на фоне идёт обсчёт главы.

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

Я предположил, что когда HTML разбирается прямо в теле документа, браузер делает какие-то дополнительные действия, чтобы элементы могли в нужный момент показаться на странице. Например, поиск и применение соответствующих CSS-правил. Лично мне эти действия на данный момент не нужны: мне нужно как можно быстрее передать содержимое главы в виде DOM-дерева прямо в JavaScript. Как заставить браузер не парсить определённый фрагмент документа? Правильно, закомментировать его:

<div id="window">
  <div id="content">
    <!--
    <p>В департаменте… но лучше не называть, в каком департаменте…</p>
    -->
  </div>
</div>


Смех смехом, но время парсинга страницы сократилось до 350 мс. А комментарий — это ведь полноценный DOM-элемент, к которому можно обратиться через JavaScript и получить его содержимое:

var elems = document.getElementById('content').childNodes;

for (var i = 0, il = elems.length; i < il; i++) {
  var el = elems[i];
  if (el.nodeType == 8) { //comment
    var div = document.createElement('div');
    div.innerHTML = el.nodeValue;
    // внутри div теперь полноценное DOM-дерево, с которым можно работать
    break;
  }
}


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

Расчёт размеров страниц


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

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

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

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

Для получения необходимых характеристик элемента нужно обратиться к его CSS-свойствам. За основу я взял функцию css() из jQuery:

function getCSS(elem, name) {
  if (elem.style[name]) {
    return elem.style[name];
  } else {
    var cs = window.getComputedStyle(elem, "");
    return cs && cs.getPropertyValue(name);
  }
}


Так как мне нужно было получить сразу довольно много свойств, это функция, судя по профайлеру из Web Inspector (имеется в виду десктопный браузер, на айфоне таких инструментов отладки нет, что сильно усложняет работу), была самой медленной. Как оказалось, обращение к getComputedStyle() — очень дорогое в плане производительности. Поэтому я модифицировал эту функцию, чтобы можно было отдать массив свойств, которые нужно получить, а также убрал проверку elem.style[name], так как в 99% случаев элементам не выставлялись CSS-свойства через объект style и эта оптимизация скорее вредила, чем помогала:

function getCSS(elem, name) {
  var names = (typeof name == 'string') ? [name] : name,
    cs = window.getComputedStyle(elem, ""),
    result = {};
  
  for (var i = 0, il = names.length; i < il; i++) {
    var n = names[i];
    result[n] = cs && cs.getPropertyValue(n);
  }
  
  return (typeof name == 'string') ? result[name] : result;
}


После такой оптимизации функция getCSS() не попадала даже в первую тройку самых медленных функций :).

Следующий шаг: правильно «размазать» расчёт страниц во времени. Дело в том, что пока выполняется JS, интерфейс браузера полностью блокируется, а также вступают в действия ограничения на время выполнения скрипта. Могла сложиться ситуация, что экран «застынет» секунд на 20—30, а потом и вовсе вывалится с ошибкой о превышении таймаута на выполнение. Современный способ избавления от таких проблем — Web Workers, но мобильный Сафари их не поддерживает. Поэтому будем использовать проверенный «дедовский» метод, работающий во всех браузерах: вызывать каждую итерацию обсчёта страниц через setTimeout(). Примерный код этого решения:

function calculatePages(elems, callback) {
  // elems — массив элементов, которые нужно обсчитать
  var cur_elem = 0;
  
  var run = function() {
    createPage(elems[cur_elem]); // делаем обсчёт страницы
    
    cur_elem++;
    if (cur_elem < elems.length)
      setTimeout(run, 1);
    else
      callback(); // обсчёт окончен
  };
  
  run();
}


Функция работает следующим образом. Например, нам нужно обсчитать 30 элементов первого уровня. Отдаём массив этих элементов в функцию calculatePages(), внутри которой создано замыкание в виде функции run(), которая является одной итерацией обсчёта. Когда закончили считать проверяем, остались ли ещё элементы в массиве. Если да, то через setTimeout() вызываем новую итерацию, иначе вызываем callback-функцию, сообщая, что расчёт окончен и можно двигаться дальше.

У такого подхода есть один важный аспект — это нагрузка на одну итерацию. В данном случае — это сколько элементов нужно обсчитать за один вызов функции run(). Если, например, считать один элемент за одну итерацию, то интерфейс для пользователя будет максимально отзывчивым, но общее время расчёта всей главы может увеличиться в 2—3 раза из-за накладных расходов, возникающих при запуске функции через setTimeout(). Если будем считать 10 элементов за один проход, то общее время обсчёта главы снизится, но также снизится отзывчивость интерфейса и повысится риск не пройти по таймауту, если параграфы будут очень большими.

Поэтому нужно найти некую золотую середину, чтобы и время расчёта не сильно увеличивать, и не снижать отзывчивость интерфейса. Я решил ориентироваться не на количество элементов первого уровня, а на их объём, который можно получить через свойство innerHTML или textContent. В качестве порогового объёма методом проб и ошибок было выбрано значение в 5 КБ. Перед вызовом calculatePages() я делил все объекты на группы: как только суммарный объем одной группы становился больше 5 КБ, она закрывалась и создавалась новая. Соответственно, расчёт размеров страниц вёлся не по отдельным элементам, а по группам.

Удаление элементов


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

function emptyElement(elem) {
  elem.innerHTML = '';
}


Однако «самый простой» не всегда означает «самый быстрый» — как показали замеры, вот такой способ работает намного быстрее:

function emptyElement(elem) {
  while (elem.firstChild)
    elem.removeChild(elem.firstChild);
}


Пожалуй, пока всё. В этой статье были рассмотрены некоторые особенности парсинга и обсчёта больших объёмов данных на маломощных устройствах. На практике все описанные трюки оказались очень эффективными. Например, я протестировал главу объёмом более 1 МБ: наша читалка смогла её переварить где-то за 30—40 секунд, в то время как другие (причём довольно популярные) читалки из AppStore, написанные на Objective C/C++, попросту падали.

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

Сергей Чикуёнок
Автор: @imobilco
Аймобилко
рейтинг 31,00
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Комментарии (98)

  • +1
    Огромное спасибо! Я многое познал для себя, осталось начать использовать.
  • +5
    Сергей, просто отличная статья. Очень хорошо поможет тем, что будет создавать что-то подобное.
  • +5
    Надо же, корпоративный блог и по делу (:
    Читалка забавная, на днях попользовался даже немного
  • +2
    жесть, дорогой проект вышел
  • –22
    Ту часть где вы кинул Тему вы забыли? :D
    • +14
      А почему вы решили, что мы его кинули? Потому что он об этом в блоге у себя написал?
      • –3
        Как оперативно :D Ну начнем с того, что весь дизаин так и кричит, что это его работа. И надо же — в его блоге это написано. И вообще вы мне ребята не нравитесь и айфонсру тоже. И смысл ему обманывать? Если выбирать кому верить я выберу его, хотя далеко не его фанат.
      • 0
        Чет я найти ничего такого у него не могу. Конечно, дело в руках скорее всего, но от ссылки не откажусь.
        • НЛО прилетело и опубликовало эту надпись здесь
    • +4
      давайте-ка без вот этих глупостей! тут офигенная статья про оптимизацию в неочевидных вещах, а вы с Темой
    • +6
      привет, «–271,0»! как дела, как семья?
      • +2
        уже холоднее чем в космосе…
  • –3
    даёшь исходники! :)
    • +2
      исходники вроде итак можно подсмотреть, это же обычный javascript
      • –2
        ты думаешь, они не пожаты? о_О
        • +1
          jsbeautifier.org и подобные думаю с этм справятся.
          код вполне читабельный
  • +1
    В Хроме 5 с фоном не лады. Серое вместо белого.
    • +1
      Да, некоторые ребята жаловались на это, но я не могу поймать баг. Какая у вас ОС?
    • –2
      да и не только там, она по сути тока под мобильный сафари работает нормально
      • –1
        конкретнее, у меня не работает в хроме, опере мобайл 9 и 10
      • 0
        Мобильная версия онлайн-читалки пока не делалась, так как требуется совершенно другой интерфейс и подход к разбору данных. Но она обязательно появится.
        • 0
          зачем другой интерфейс если есть большой тач скрин?
          • 0
            Вы про айпад? Там тоже нужно дорабатывать, чтобы быстрее всё работало.
            • 0
              я про винмобайлы с тачскрином, где собственно опера мобайл 9 и 10
              • 0
                А, ну там тем более нужно оптимизировать. Как минимум, нужно одну страницу вместо двух выводить, оптимизировать по производительности и как-то иначе показывать настройки.
                • 0
                  угу, а то такой облом вышел, думал ща книжку в самолете почитаю а тут (
                  • 0
                    Вы учитывайте, что это только первая бета-версия. В обязательных планах: cache manifest и хранение главы в local storage, чтобы мобильные пользователи могли при отключённом интернете продолжать читать
  • 0
    Хорошо, аккуратно. Номеров страниц не хватает.
    • 0
      Страницы без проблем можно пронумеровать в пределах одной главы, но если делать сквозную нумерацию всей книги, то возникает ряд проблем: нужно сначала загрузить всю книгу и просчитать все страницы + делать это каждый раз, когда пользователь меняет размер окна или настройки. А это довольно сильный провал в производительности. У меня в TODO стоит этот пункт, попробую что-нибудь придумать.
      • 0
        Не нужно пересчитывать. Экран должен быть фиксированного размера, особенно если речь про мобильные устройства.

        На первой странице достаточно написать 1 и 2, при желании можно в фоне досчитать до конца, пока я читаю первые две, а без желания оставить так как есть, и просто менять при листании. Это точно производительность не затронет.
        • 0
          Всё не так просто. На мобильных устройствах вроде айфона действительно экран фиксированного размера, но расчёт всей книги может занять несколько минут. Тем более, пользователь в любой момент может поменять настройки чтения (например, находясь где-нибудь ближе к концу книги), а это означает новый пересчёт всей книги + сброс кэша расчётов остальных книг пользователя.
          • +1
            Пусть даже несколько минут. Мы ведь никуда не торопимся. Несколько минут я буду читать несколько страниц, и пусть оно пока асинхронно считается, вы же на яваскрипте пишете. Во всяком случае, так поступает хардварная читалка PocketBook, которая также вынуждена обходиться весьма скромным ЦПУ. А если пользователь ближе к концу что-то такое решит — значит сам виноват, останется без пажинации. Насколько част такой сценарий? ИМО, важнее создать позитивное впечатление у 98,571% пользователей, которые ведут себя предсказуемо, а не предусмотреть перфектность для всех случаев вообще, за счёт ущемления большинства.
            • 0
              Пусть даже несколько минут. Мы ведь никуда не торопимся.

              Ну вы почитайте отзывы к предыдущим версиям приложения booq :)

              Тем более, на айфоне есть другие (и бесплатные) читалки, на фоне которых наша смотрелась бы очень блекло. Нумерация страниц не может быть конкурентным преимуществом, если из-за этого читалка работает в несколько раз медленнее остальных.
      • 0
        а почему бы не отдать расчеты серверу?
        • 0
          и вообще, почему бы не отдавать на клиент небольшой кусок текста, где с ним шустренько и работать?
        • 0
          Как вы себе это представляете?

          Подсказка: размер страницы зависит от гарнитуры и размера шрифта (в том числе системного, установленного в браузере пользователя), интерлиньяжа и размера окна браузера. И всё это пользователь может поменять в любую секунду.
          • 0
            а скрипт может в любую секунду передать на сервер все эти метрики, разве нет?
            • 0
              Может. Получается, что на сервере должны быть запущены тысячи экземпляров разных браузеров с разных платформ (на разных платформах по-разному текст отрисовывается)?

              Какая тогда будет выгода пользователю, если на клиенте это всё будет выполняться в несколько раз быстрее? Сейчас расчёт главы среднего размера на не самом быстром клиенте делается не более чем за 100 мс
              • 0
                Не знаю, насколько ресурсоемко для сервера будет все обсчитывать (тут надо эксперементировать). Подозреваю, что при должном кешировании, можно обеспечить быструю отдачу обсчитанного контента.
                Суть в том, что 100 мс стоили 7 месяцев вашей работы. Мне интересно, насколько была бы жизнеспособной и трудоемкой конфигурация (и была бы?) с серверными расчетами.

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

                • 0
                  Поверьте, эти месяцы стоили того :) Я заложил хороший фундамент для наших следующих продуктов.
              • 0
                Opera на айфоне же как-то так и работает — рендерит страницу на сервере и отдает картинку. Вполне себе решение для мобильных платформ, хотя у вашего, конечно, свои преимущества есть.
                • 0
                  Opera на айфоне же как-то так и работает — рендерит страницу на сервере и отдает картинку.


                  И все увидели, что в итоге получается :)

                  У рендеринга на сервере есть две большие проблемы. Первая — это необходимость каждый раз загружать новую книгу, когда пользователь что-то поменял в настройках. Вторая — вы заставляете пользователя быть постоянно подключенным к интернету, даже если он решил почитать книгу в метро, в самолёте или отдыхая в другой стране.
                  • 0
                    Кстати, если не сложно, в двух словах, а что получилось? Я только их рекламный ролик видел, айФона у меня нет.
  • 0
    • 0
      Customer Reviews радуют, случайно запостил
    • 0
      Внесу ясность насчёт отзывов. Если смотреть iTunes через сайт, то там показываются отзывы к версии 0.6, которая действительно была ужасна, но которую нам пришлось запостить из-за ряда проблем с предыдущей версией приложения.

      Последняя версия — 0.7, в ней присутствует описанный здесь оптимизированный движок. К ней отзывы по-лучше :)
  • 0
    Google Chrome 6.0.408.1 dev Windows XP SP3
    На остальных страницах текста нет вообще.

    Под другими браузерами всё тип-топ. Сервис супер!
    • +1
      Так сразу становится, или после каких-то действий (вижу, что у вас шрифт другой в книге)?
    • +1
      Используете блокировщик рекламы?
    • +1
      Да, кстати, возможно мешают какие-то расширения. Можете прислать список тех расширений, которые стоят у вас в Хроме?
      • 0
        Точно. Отрубил AdThwart всё заработало.
        • +1
          Спасибо, попробую сделать так, чтобы и с ним работало
  • 0
    пилю один сайт, в котором контент разбивается на блоки подобным образом…
    у меня оно, конечно, пока все довольно медленно, но благодаря этим статьям, возможно, оптимизирую его :)
    спасибо)
  • 0
    текст в книжке иногда обрезается если на странице несколько заголовков, скрин
    • 0
      Да, это баг расчёта размера страниц на «сложных» книгах (где много вложенных элементов с разным форматированием), работаю над этим
  • +5
    Отличная статья. Где-то полгода назад я загорелся идеей сделать удобную онлайн-читалку для десктопных браузеров и начал работы в этом направлении — некоторые идеи пересекаются с изложенным выше. :)

    ЗЫ. После обнаружением сервиса bookmate.ru разработка своего велосипеда прекращена. :)
  • +4
    Если не ошибаюсь, то для анимации используется jTweener, для чего тогда грузить целый jQuery, если он используется только для селекторов и обертки над ajax, или он не только для этого? Вполне можно обойтись каким-нибудь YASS, а для ajax обертку написать. А вобще есть еще bookmate.ru
    • 0
      jQuery используется для CSS-селекторов, работы с событиями (в том числе нормальная делегация событий), аякс, некоторые простые анимации. Я решил не изобретать новый велосипед и использовать jQuery для онлайн-читалки, так как хороший и проверенный инструмент. Так как это декстоп, то описанных проблем с производительностью нет.
  • +2
    Опера 10.5 бета, убунта. Намертво подвешивает браузер.
    У хромиуме, напротив, все хорошо.
    • +6
      Блин, ну почему, если написано «не влезай, убъет», так хочется проверить, а точно убъет? Намертво подвешивает, гарантирую :)
      • +1
        Это русская традиция =)
      • +3
        Ну, хомм, вы программист на всю голову. Поздравляю вас :).
    • 0
      10.5 бета или всё же 10.6 альфа? Сейчас посмотрю
      • 0
        Version information
        Version 10.54 Internal
        Build 21867
        Platform Linux
        System i686, 2.6.31-14-generic

        Browser identification
        Opera/9.80 (X11; Linux i686; U; en) Presto/2.5.24 Version/10.54
        • 0
          Постаил себе эту версию. Когда у вас возникают зависания? Сразу после загрузки страницы?
          • 0
            Она подвешивает сразу же, иногда отпускает. При нажатии на какую-нибудь другую главу снова подвешивает. Иногда отпускает, иногда нет.
            Похоже что ему не нравится подгрузка текста, сейчас попробую посмотреть подробнее.
          • 0
            профайлера в драгонфлае нет.
            Глава «Тамань» загружается секунду, после загрузки браузер подвисает секунд на 5.
            В оглавлении все работает хорошо.
            Глава «Часть вторая / Княжна Мери» грузится 7 секунд, потом браузер умирает без конвульсий.
            • 0
              Ок, спасибо, проверю, что там такое
              • 0
                С оперой вообще какие-то проблемы (традиционные для браузера, полагаю) — 10.53 (8343), OSX: листаем, листаем, листаем -> о книге -> продолжить чтение -> браузер зависает где-то на минуту (при это интерфейс немного «бьётся»).
              • 0
                Version information
                Version 10.60 Internal
                Build 6347
                Platform Linux
                System i686, 2.6.31.6
                Browser identification Opera/9.80 (X11; Linux i686; U; en) Presto/2.5.28/2.5.23 Version/10.60

                10.6 альфа, гента. Глава тамань открывалась секунд десять, браузер выжрал 90% проца. Потом его отпустило, главу про княжну мери открывать не рискнул.
  • 0
    > Блог компании Аймобилко
    > Как создавалась Айчиталка.

    Тогда уж «Как создавалось Айчиталко»
  • +2
    а есть такой сервис для которого сам грузишь книги чтобы их потом читать ??
    =))
    • +1
      man cp
    • +2
      У нас можно закачивать свои книги себе в аккаунт, но пока нельзя читать (есть некоторые технические сложности). Обязательно сделаем в ближайшее время.
    • +5
      bookmate.ru
  • 0
    на десктопе работает отлично (chrome 5.0.375.55, linux), но на телефоне с андроидом тормозит и на экране мобильника всё как-то мелко.
    • 0
      Интерфейс онлайн-читалки ещё не оптимизировался под мобильные устройства.
  • 0
    Супер, интересно было прочитать все от начала до конца.
    Прям триллер — «Битва за время».
  • +4
    Господи зачем этот архаизм с переплетом и обрамлением из книги, вы бы еще эффект листания туда зафигачили.
    • +6
      Вы удивитесь, но эффект листания есть :)
    • +2
      так они и зафигачили. под файрфоксом работает.
      я, кстати, тоже не понимаю, зачем с помощью компьютера имитировать «интерфейс книги».
      • +2
        Сделайте вид не книжный, а «портянкой» и будет отличаться от книги.
  • +4
    Уважаемые владельцы блога! Пользуясь случаем не могу не поинтересоваться. Правду ли Тема писал, когда запостил в свой жж, что вы его с оплатой кинули?
    • +2
      Могу сказать только одно: тот иск, которым пугал Тёма в своём жж, мы с нетерпением ждём уже больше года, но его почему-то нет.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Добавил в TODO, возможно, сегодня сделаю
  • +10
    Сергей, вы — научный исследователь-теоретик в области html/css/js. У вас есть возможность решать задачи, на которые у остальных разработчиков-практиков не хватает времени (средств, мозгов). Cпасибо вам, что вы есть и делитесь с нами вашими разработками, и спасибо компании Аймобилко, что дает вам возможность заниматься этими научными исследованиями под своим крылом.
  • 0
    "Следующий шаг: правильно «размазать» расчёт страниц по времени"?
  • 0
    Ребят, я не знаю как у вас че создавалось, но… купил книгу «Эффективное общение» Кейт Кинан. А она не открывается.
    Вот так вот.

    Айчиталка вообще вылетает при открытии книги…
    А вот booq пишет ошибку: content1.xhtml TypeError: Result of expression «c» [undefined] is not an object.
    • +2
      Приношу извинения: проблема была в самой книге. Сейчас исправил, попробуйте снова открыть. Для booq нужно удалить книгу и заново скачать, а для онлайн-читалки (если книга снова не открывается) почистить кэш
      • +1
        Спасибо за оперативность, не ожидал… теперь все заработало)
  • 0
    Хабраиндекс стал красив.
  • +2
    Да, забыл спросить, а как вы замеряете время выполнения отдельно взятых скритов и функций?
    • 0
      Записывал время до и после выполнения функции через (new Date).getTime() и сравнивал время. Но есть некоторые нюансы, о них чуть подробнее напишу в следующей части.
  • 0
    Супер статья! Спасибо огромное!
    Жду продолжения с нетерпением!

  • 0
    Видел в своей почте анонс Айчиталки-в-железе. А что у нее внутри? Имеете отношение?
    • 0
      Пока нет. Читалка используется нативная (которая с железкой идёт), а движок booq используется для просмотра демо-версий книг. Потом планируем написать полностью своё приложение со своим движком
  • 0
    От покупки меня удерживает только наличие сенсорной плёнки (знаю, что
    из-за неё экран будет очень заметно бликовать). Нет ли планов сделать
    устройство без неё, а ещё лучше — с инфракрасной сенсорной рамкой?

    В плане прошивки: хотелось бы иметь доступ к словарю.

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

Самое читаемое Разное