Localstorage explorer
Делали тут одну игрушку и понадобилось сохранять статус и уровень, чтоб после перезагрузки не начинать сначала. Ну и решили в localStorage сохранять. Но как дебажить? Оно же всё время записывает данные и потом начинает откуда-то не сначала! Нужно что-то типа эксплорера, чтоб ненужное удалять. Иду искать в гугл, и...ничего! Ну не то чтобы совсем ничего, есть расширения для браузеров, но это нужно для каждого браузера, да и под мобильные не будет, а нам надо на мобильном тоже. Был ещё еле еле рабочий скриптик, не буду его пиарить, можете сами по названию поискать, он примерно так и называется.
Ну, в общем, не долго думая, сажусь писать свой велосипед (или не велосипед?) и вот что получилось. Вот тут скрипт на gist одним файлом (не считая зависимости w3.css): https://gist.github.com/yesasha/5e8a...b0d8459c7fd616. Если нужно в свой проект этот файл кидаем в папку и испоьзуем. Вот тут можно на codepen поиграться https://codepen.io/yesasha/pen/ppdyWL. За одно увидите что другие проекты от codepen хранят в вашем localStorage. Немного поясню как оно работает.
|
Цитата:
Обработка нажатий на определенные элементы таблицы интересно сделана. Я бы, как минимум, вынес выполнение операций (удаление, добавление и .т.п.) в отдельные функции и избавился от повторения одного и того же кода. Не проверяется доступен ли элемент коллекции под определенным ключом или нет. Взаимодействие с локальным хранилищем осуществляется без проверки его доступности + вне try catch. Функция "removeAllSortingClasses" и 6 функций "sort[\d]" вызвали пару вопросов: 1. Почему в "removeAllSortingClasses" не воспользовались циклами? 2. Зачем N функций, если их отличия минимальны, почему не 1 с несколькими агрументами для управления поведением? Заранее прошу прощения, но я бы не стал пользоваться Вашим решением, много Индусского кода. |
Вложений: 1
Я вот тоже подумал, что индусский код, хоть и рабочий, может магическим образом оттолкнуть пользователей...
Код был ещё более индусским, но в определённый момент хочется сказать и так сойдёт. Благодаря же Вашим замечаниям провёл рефакторинг, узнал некоторые новые вещи, например про навигацию по таблице. Многие функции объединились. От многих избавился. Теперь состояние просто хранится в глобальных переменных. Теперь содержимое localStorage перечитывается и при сортировке. Более того, это помогло всё убрать в одну функцию рендеринга. А что именно интересного в обработке нажатий? LocalStorage не выбрасывает исключений. И ничего страшного не происходит, если удалить элемент дважды. С classList тоже самое. Какие ещё коллекции не проверяются? Обновил версии по ссылкам, теперь там новые версии. Старую же прикрепил сюда для сравнения. |
Цитата:
Цитата:
Не особо разбирался в вашем коде, но более чем уверен, что строки 93-111 можно сократить. } else if (classList.contains('index') && !classList.contains('asc') && !classList.contains('dsc')) { render(0, 'asc'); } else if (classList.contains('key') && !classList.contains('asc') && !classList.contains('dsc')) { render(1, 'asc'); } else if (classList.contains('value') && !classList.contains('asc') && !classList.contains('dsc')) { render(2, 'asc'); } else if (classList.contains('index') && !classList.contains('asc') && classList.contains('dsc')) { render(0, 'asc'); } else if (classList.contains('key') && !classList.contains('asc') && classList.contains('dsc')) { render(1, 'asc'); } else if (classList.contains('value') && !classList.contains('asc') && classList.contains('dsc')) { render(2, 'asc'); } else if (classList.contains('index') && classList.contains('asc') && !classList.contains('dsc')) { render(0, 'dsc'); } else if (classList.contains('key') && classList.contains('asc') && !classList.contains('dsc')) { render(1, 'dsc'); } else if (classList.contains('value') && classList.contains('asc') && !classList.contains('dsc')) { render(2, 'dsc'); } |
Те строчки действительно получилось сократить и очень сильно. Но вот стоило ли оно того? Ведь было потрачено время, а оно и так работало!
Насчёт доступности хранилища, замечание полезное. Добавил проверку доступности в функцию рендеринга. Не уверен насчёт полезности данного подхода. Плюс добавил ещё несколько полезных вещей. Например фокус возвращается на поле ввода после клика по кнопке, что позволяет быстрее добавлять новые записи. В панели статуса отображается доступность хранилища и кол-во записей. |
Цитата:
|
Ну, некоторые изменения были важны, например проверка доступности. Странно, что я не замечал ту статью.
А на остальное нет однозначного ответа для всех. Это каждый для себя должен ответить, в зависимости от того кем он хочет стать! Программистом или кодописцем) Но в целом если код более понятен, то потом проще выявить баги и добавлять новые функции. Понятен, не значит меньше кода, а то писал я тут букмарклет... |
Yesasha, если код недостаточно ясен для понимания, в любом яп есть такая вещь, как комментарии, которые эту неясно могут легко исключить.
Никого до вас не встречал, кто бы говорил, что Индусский стиль написания кода улучшает его общую понятность и скорость написания. Глупость, имхо. Поддерживать такой код еще то удовольствие... |
А я не говорил что индусский стиль улучшает! Я сказал, что мне удалось сократить код и он СТАЛ понятнее. Но я мог его не сокращать и оставить как есть, если бы решил, что оно того не стоит, в смысле тратить время на проект, который никому не нужен, к примеру. Более того, я не видел изначально, что получится сократить на столько! А индусский стиль не столько понятен, сколько он сам по себе возникает, когда добавляешь много новых функций, просто дописывая новый код, не ориентируясь на уже написанный. А потом, есть такая вещь, как рефакторинг, как раз для того, чтобы взглянуть со стороны и переписать по другому. И вряд ли можно всегда сразу писать идеально.
|
Цитата:
|
Интернет експлорер преподнёс пару сюрпризов. Оказалось, что методы add и remove у classList не поддерживают множественные аргументы.
Добавил реакцию на событие storage. Теперь изменения сделанные в одной вкладке/окне, сразу видны во всех других. И тут скрывался очередной сюрприз! Все ие от этого страдают, пришлось добавить throttler. В принципе, я и так собирался это сделать, чтоб перерисовывать DOM через requestAnimationFrame. |
Хочу рассказать ещё несколько вещей на тему локального хранилища.
У него есть ограничения на размер хранимой информации и этот размер равен примерно 5 мегабайт для каждого origin. Может отличаться от браузера к браузеру, но мы же хотим чтобы всё работало в разных браузерах, значит нужно ориентироваться на минимум. Но что значит эти 5 мегабайт? Это значит что мы примерно можем сохранить строку из 5242880 англ. символов. И вот тут всплывает не самая очевидная деталь - ключи тоже занимают место. То есть мы можем сохранить 5 мег строку под пустым ключом. Или под ключом длиной 5 мег пустую строку. Ну и все промежуточные варианты, конечно. И логично было бы хранить всё одной строкой и не тратить место на ключи, но тогда возникает проблема производительности, ведь эту длинную строку придётся каждый раз перезаписывать целиком! Поэтому нужно искать компромисс между кол-вом ключей и размером значений. Кстати, размер в 5 мегабайт можно и обойти, и я давно пришёл к этой идее и хотел даже библиотечку написать, но потом нашёл ещё людей, которые пришли к тому же! Надёжный localStorage для букмарклетов, Cross-Domain LocalStorage. Что касаемо моего эксплорера, то во время теста на максимальное заполнение (посмотреть его можно тут, только он совсем не юзерфрендли, не совсем понятно что он делает, если не заглядывать в код, но я создавал его для себя, а не для общего пользования), выяснилось, что браузер то не справляется с таблицей на тысячи строк... :cray: И тут я пустился в размышления и понял, что единственный способ "отобразить" тысячи и больше единиц информации - это не отображать её в DOM, а держать в переменной javascript, и отображать только видимую часть. И это решит и проблему производительности и проблему памяти. Только вот думаю стоит использовать какой-нибудь фреймворк для таких манипуляций. Если же смотреть только на производительность, то мой подход с переиспользованием элементов оказался не плохим вариантом! Дело в том, что это единственное, что смог осилить Интернет Эксплорер! И конкатенация строк в цикле с последующей записью в innerHTML таблицы, и insertAdjacentHTML в цикле, показали в десятки(!) раз худшую производительность! И если бы не IE, то я бы сказал, что конкатенация строк, то есть пересоздание таблицы в памяти с последующей записью в innerHTML нормальный и производительный способ! Он показал в 2 раза лучшую производительность в Хроме. И в новой версии я бы использовал именно этот подход. А так пришлось оставить всё как было... Вот тут и эксперименты: 1, 2, 3 |
Что можно хранить в локальном хранилище в таких объемах?
Почему именно в локальном хранилище? |
Ну почему, потому-что простые вещи, как уровень игрока в игре, проще хранить именно в нём, это и послужило началом для этой темы. А дальше я просто делюсь тем что ещё знаю об этом. Это, конечно, не единственный способ сохранять информацию! Простые вещи можно хранить в куках, например, но там совсем мало места и они шлются каждый раз на сервер. Ещё localStorage хорошо поддерживается браузерами и не спрашивает разрешения пользователя, и с ним проще работать чем с куками! Так что для простых вещей самое то.
А о каких "таких" объёмах речь? Пока речь идёт о тексте, кажется что 5 мегабайт это много, но как только дело дойдёт до картинок, много вы туда сможете сохранить? Сейчас эра вебаппликаций, вот вы загружаете фото в соц. сеть и вдруг раз, пропал интернет. Картинка временно сохраняется локально, а потом синхронизируется с сервером при появлении связи. |
Yesasha, вы какую-то глупость написали.
Браузер самостоятельно кеширует загруженные изображения, достаточно настроить заголовки отдаваемые сервером, поэтому нет абсолютно никакой необходимости сохранять их в localStorage. Все используемые в работе данные обязаны храниться только на сервере. Если lvl персонажа хранится на клиенте и используется для каких-либо расчетов, то это колоссальная дыра. Данные персонажа можно передать клиенту при инициализации и сохранить их в ram. Т.е. опять же нет необходимости хранить данные персонажа на клиенте в localStorage. PS. а изображения в localStorage вы храните в base64? |
Цитата:
Цитата:
Цитата:
Вон товарищ зачем-то хочет в PNG сохранять историю действий. По моему ему идеально подошёл бы localStorage. Вот уж не знаешь что глупее, хранить текст в картинке или картинку в тексте! Цитата:
Цитата:
А Вы для каждого простого приложения держите сервер и проводите регистрацию пользователей? В любом случае речь идёт об offline first web app, то есть приложение, которое должно в первую очередь работать без наличия интернета. И многие принципы, которые были актуальны раньше, тут уже не подходят. |
А тем временем я написал "полнофункциональное" приложение для просмотра и редактирования localStorage, sessionStorage и cookie на своём сайте и с возможностью кроссдоменного доступа через букмарклет. Так же приложение доступно оффлайн через технологию application cache.
Storage Explorer UPD: Ссылка на репозиторий https://github.com/yesasha/storage-explorer |
Часовой пояс GMT +3, время: 09:57. |