Присылаю вам пламенный привет🔥💌 с прошедшей конференции Dump из Питера! На конфе было круто - есть треки докладов по фронт, бек-разработке, менеджменту и тестированию.
(А вот в Питере сейчас не круто - дубак и ветруган🥶)
Доклады огонь, спикеры топ, но сегодня хочу поделиться именно Java-задачками, которые были на стенде у компании PVS-Studio (делают статические анализаторы кода). Суть такая - есть 4 фрагмента реального кода из разных opensource-проектов, в каждом из которых есть бага🐞
Задача - найти ее.
Задачки непростые, для разработчиков, поэтому если немного подумав так и не нашли проблемы в коде - вот вам подсказки:
1 - ищем нестабильность в работе цикла
2 - проблема кроется в математике
3 - бага кроется где-то в области всего блока if
4 - смотрим на операцию побитового сдвига и анализируем, что с ней не так
Позже разберу правильные ответы - заодно сможете себя проверить и наградить виртуальной/шоколадной медалькой🥇🥈🥉
(А вот в Питере сейчас не круто - дубак и ветруган🥶)
Доклады огонь, спикеры топ, но сегодня хочу поделиться именно Java-задачками, которые были на стенде у компании PVS-Studio (делают статические анализаторы кода). Суть такая - есть 4 фрагмента реального кода из разных opensource-проектов, в каждом из которых есть бага🐞
Задача - найти ее.
Задачки непростые, для разработчиков, поэтому если немного подумав так и не нашли проблемы в коде - вот вам подсказки:
1 - ищем нестабильность в работе цикла
2 - проблема кроется в математике
3 - бага кроется где-то в области всего блока if
4 - смотрим на операцию побитового сдвига и анализируем, что с ней не так
Позже разберу правильные ответы - заодно сможете себя проверить и наградить виртуальной/шоколадной медалькой🥇🥈🥉
🔥7❤1👍1
Грамота от Кузьмича
Присылаю вам пламенный привет🔥💌 с прошедшей конференции Dump из Питера! На конфе было круто - есть треки докладов по фронт, бек-разработке, менеджменту и тестированию. (А вот в Питере сейчас не круто - дубак и ветруган🥶) Доклады огонь, спикеры топ, но сегодня…
Счастливого понедельника! Как обещал - публикую ответы к задачкам выше:
#1
Имеем цикл
П.С. Вообще бесконечные циклы - это нормально, до тех пор пока в них у вас описаны способы выхода, в один из которых можно гарантированно прийти - это может быть и break и return, выброс исключения, да даже простихосспаде System.exit(0) - что угодно, лишь бы из цикла можно было как-то выбраться. Либо рассчитывайте на то что приложение придется прерывать вручную.
#2
Тут пара проблем. Во-первых - можно нарваться на ArithmeticException при делении на 0.
Но важнее здесь то что при делении capitalized / words.size() происходит деление целого числа (int) на целое число (int) и результатом будет тоже int, а значит никаких дробей мы ни при каком раскладе не получим и сравнение не принесет того смысла который мы хотели. Например:
Решением может стать явное преобразование одного из int к double, что бы результат деления тоже дал double:
#3
Собственно, читаем исходную строку кода с if новым взглядом:
if ([значение от -128 до 127] меньше [255]) - очевидно что это условие будет выполняться всегда.
#4
Проблема кроется в этой строке:
Начну с вводной. Часть
или просто
Почему тут вообще решено было использовать операцию левого битового сдвига << ? Многим эта тема кажется стремной и неоправданной, но представьте что ваш метод - "горячий", его вызовы в приложении происходят по 10000 раз в секунду, а то и больше - тогда конечно вы будете гнаться за каждой милисекундой в ущерб читаемости. Загляните ради любопытства в реализацию метода Math.pow() - и ужаснитесь сколько всего там происходит. Оператор же побитового сдвига прост как сапог - двигает биты в памяти влево на N позиций.
Поэтому побитовый сдвиг может заменять обычные арифметические операции умножения/деления числа на двойку или степени двойки когда вам реально нужен скоростной код. Кейс правда точно не про обычные API/UI автотесты, у нас таких жестких требований к производительности не будет почти никогда.
Теперь про причину ошибки в упомянутой строке - проблема в интовом типе 1 (единицы) в выражении:
Все числовые литералы - неявно int-ы (если только у них не указаны постфиксы: L, l (для long), D, d (для double), F, f (для float)).
Если j окажется больше или равно 31 - мы получим переполнение типа, знакомое нам и по обычным арифметическим операциям (ну например System.out.println(2000000000 + 2000000000); //result: -294967296).
#1
Имеем цикл
while (count < 4) - который опирается на значение count, которое никогда внутри цикла не меняется. Значит цикл бесконечный. Например попав в цикл с count = 3 - count всегда будет оставаться = 3, значит условия цикла будет верно, значит мы будем в нем кружиться до тепловой смерти вселенной.П.С. Вообще бесконечные циклы - это нормально, до тех пор пока в них у вас описаны способы выхода, в один из которых можно гарантированно прийти - это может быть и break и return, выброс исключения, да даже простихосспаде System.exit(0) - что угодно, лишь бы из цикла можно было как-то выбраться. Либо рассчитывайте на то что приложение придется прерывать вручную.
#2
return capitalized / words.size() < 0.2;Тут пара проблем. Во-первых - можно нарваться на ArithmeticException при делении на 0.
Но важнее здесь то что при делении capitalized / words.size() происходит деление целого числа (int) на целое число (int) и результатом будет тоже int, а значит никаких дробей мы ни при каком раскладе не получим и сравнение не принесет того смысла который мы хотели. Например:
capitalized = 1;
words.size() = 5;
capitalized / words.size() = 1 / 5 = 0 - потому что произошло целочисленное деление.
Решением может стать явное преобразование одного из int к double, что бы результат деления тоже дал double:
return (double) capitalized / words.size() < 0.2;#3
if (endKey[i] < 0xff) - вот корень зла. Здесь мы имеем условие, которое будет выполняться всегда - а значит либо это условие описано неправильно, либо if тут вообще лишний. Почему условие будет выполняться всегда? Разбираем значения и типы данных:byte[] endKey - массив байт, endKey[i] - один байт из массива, может хранить значение от -128 до 1270xff - число в 16-ричной форме записи, в человеческом виде это число 255.Собственно, читаем исходную строку кода с if новым взглядом:
if (endKey[i] < 0xff)if ([значение от -128 до 127] меньше [255]) - очевидно что это условие будет выполняться всегда.
#4
Проблема кроется в этой строке:
val = val | (1 << j);Начну с вводной. Часть
1 << j - по сути аналог математического выражения 2^j (2 в степени j). В Java нет оператора степени, но есть метод Math.pow(). Без оператора побитового сдвига строчка кода выше могла бы выглядеть как:val = val | (1 * Math.pow(2, j));или просто
val = val | Math.pow(2, j);Почему тут вообще решено было использовать операцию левого битового сдвига << ? Многим эта тема кажется стремной и неоправданной, но представьте что ваш метод - "горячий", его вызовы в приложении происходят по 10000 раз в секунду, а то и больше - тогда конечно вы будете гнаться за каждой милисекундой в ущерб читаемости. Загляните ради любопытства в реализацию метода Math.pow() - и ужаснитесь сколько всего там происходит. Оператор же побитового сдвига прост как сапог - двигает биты в памяти влево на N позиций.
Поэтому побитовый сдвиг может заменять обычные арифметические операции умножения/деления числа на двойку или степени двойки когда вам реально нужен скоростной код. Кейс правда точно не про обычные API/UI автотесты, у нас таких жестких требований к производительности не будет почти никогда.
Теперь про причину ошибки в упомянутой строке - проблема в интовом типе 1 (единицы) в выражении:
val = val | (1 << j);Все числовые литералы - неявно int-ы (если только у них не указаны постфиксы: L, l (для long), D, d (для double), F, f (для float)).
1 << j - означает что единица целочисленного 4-байтного типа (т.е. 00000000 00000000 00000000 00000001 в двоичном виде) будет сдвинута на j разрядов влево. Например:1 << 2 = 00000000 00000000 00000000 00000100 в двоичной системе = 81 << 13 = 00000000 00000000 00100000 00000000 в двоичной системе = 8192Если j окажется больше или равно 31 - мы получим переполнение типа, знакомое нам и по обычным арифметическим операциям (ну например System.out.println(2000000000 + 2000000000); //result: -294967296).
👍2🔥1
Грамота от Кузьмича
Присылаю вам пламенный привет🔥💌 с прошедшей конференции Dump из Питера! На конфе было круто - есть треки докладов по фронт, бек-разработке, менеджменту и тестированию. (А вот в Питере сейчас не круто - дубак и ветруган🥶) Доклады огонь, спикеры топ, но сегодня…
Ну и окей, нам то че с того? Вот мы с вами когда пользуемся операторами +,-,*,/ - никогда не паримся, просто держим в голове что если числа с которыми мы делаем вычисления будут слишком большими - надо будет или делать до вычисления какую-нибудь проверку, или работать с long/BigInteger, или с Math.addExact(), тут джекичанских путей решения этой задачи хватает. В чем тогда бага этой строки?
Если представить это выражение чисто в виде используемых типов - проблема станет очевиднее (нет):
Целевой тип с которым мы работаем - long. А в части (1 << j) - мы получаем результат int, который воткнется в проблему переполнения раньше чем long. Поэтому что бы поправить ошибку - в коде надо явно указать что побитовый сдвиг мы делаем для long:
Похожая ошибка на более простом кейсе - как если написать код:
И расстраиваться почему это у нас для больших чисел некорректно идет умножение. Фикс:
Выводы. Их несколько.
- Математика, типы, циклы и условия - только и ждут чтобы поиметь вас, поэтому знайте врага в лицо и будьте бдительны:)
- Баги встречаются везде, даже в крупнейших проектах. Тесты и автотесты - самое годное оружие против них. Напиши автотест - сделай мир лучше!
val = val | (1 << j);Если представить это выражение чисто в виде используемых типов - проблема станет очевиднее (нет):
long = long | (int << int);Целевой тип с которым мы работаем - long. А в части (1 << j) - мы получаем результат int, который воткнется в проблему переполнения раньше чем long. Поэтому что бы поправить ошибку - в коде надо явно указать что побитовый сдвиг мы делаем для long:
val = val | (1L << j);Похожая ошибка на более простом кейсе - как если написать код:
int a = ...; //любое значение
long result = 2 * a; //результат умножения - int
И расстраиваться почему это у нас для больших чисел некорректно идет умножение. Фикс:
long result = 2L * a; //результат умножения - longВыводы. Их несколько.
- Математика, типы, циклы и условия - только и ждут чтобы поиметь вас, поэтому знайте врага в лицо и будьте бдительны:)
- Баги встречаются везде, даже в крупнейших проектах. Тесты и автотесты - самое годное оружие против них. Напиши автотест - сделай мир лучше!
🔥4❤1🙏1
Зимой распускаются не только подснежники🌼.
Мой план - стартовать экспресс-курс по продвинутой Java + автоматизации. Эдакая ступенька для роста с Junior в Middle. Сейчас определяю состав тем и технологий. Курс будет в записи, но первый поток - проведу в живую в zoom, единственный раз. Так что успевайте вписаться на рок-перфоманс🤘
Голосовалка за интересующие темы тут - https://forms.gle/Z3HSL3GhLJSkkc3G9 - топ тем из голосования войдут в курс.
Запись в список ожидания - в телегу @NeonAether. О старте продаж узнаете первыми и в личку. И следите за обновлениями в канале - об открытии набора, утвержденной программе курса и дате старта - инфа появится вот прям здесь, в этом канале🎯
Мой план - стартовать экспресс-курс по продвинутой Java + автоматизации. Эдакая ступенька для роста с Junior в Middle. Сейчас определяю состав тем и технологий. Курс будет в записи, но первый поток - проведу в живую в zoom, единственный раз. Так что успевайте вписаться на рок-перфоманс🤘
Голосовалка за интересующие темы тут - https://forms.gle/Z3HSL3GhLJSkkc3G9 - топ тем из голосования войдут в курс.
Запись в список ожидания - в телегу @NeonAether. О старте продаж узнаете первыми и в личку. И следите за обновлениями в канале - об открытии набора, утвержденной программе курса и дате старта - инфа появится вот прям здесь, в этом канале🎯
🔥6👍3
“Инстанцио!” - быстро выкрикнул Гарри Поттер, взмахнув палочкой и добавив в pom.xml новую зависимость.💫
В нашем арсеналеволшебника разработчика должно быть достаточно заклинаний библиотек, что бы разрабатывать быстро и не изобретать велосипеды. Добавим себе в копилку еще одну.
Instancio - библиотека про генерацию тестовых данных. https://github.com/instancio/instancio
“Но а как же Faker?” - спросите вы. А я поясню.
Faker (com.github.javafaker) в первую очередь генерирует отдельное атомарное значение, кусочек данных. Телефонный номер, email-адрес, строку ФИО, GPS-координату.
Instancio - предназначен для создания сложных структур данных, т.е. объектов с полями, с уровнями вложенности.
Просто для сравнения - как бы мы генерировали объект класса Person(firstName, lastName, age, phoneNumber) со случайными значениями полей с использованием faker и с использованием instancio:
🔴Faker
🔵Instancio
Конечно не обойдется без нюансов. По умолчанию Instancio будет заполнять поля объекта полностью рандомными данными, в то время как с Faker мы будем получать данные, более похожие на реальные, живые. Для примера - как будут выглядеть объекты Person, сгенерированные двумя способами выше:
Но каждому инструменту - свое применение. Резюмирая: Faker - про генерацию фейковых данных (но реалистично выглядящих). Instancio - про создание объектов, с полями, забитыми случайными данными (что может быть более актуально в unit-тестировании).
Саму зависимость Instancio можно найти здесь: https://mvnrepository.com/artifact/org.instancio/instancio
Дополнительно почитать про возможности и настройку библиотеки - тут: https://www.instancio.org/user-guide/#creating-objects (боже храни людей которые пишут документацию).
В нашем арсенале
Instancio - библиотека про генерацию тестовых данных. https://github.com/instancio/instancio
“Но а как же Faker?” - спросите вы. А я поясню.
Faker (com.github.javafaker) в первую очередь генерирует отдельное атомарное значение, кусочек данных. Телефонный номер, email-адрес, строку ФИО, GPS-координату.
Instancio - предназначен для создания сложных структур данных, т.е. объектов с полями, с уровнями вложенности.
Просто для сравнения - как бы мы генерировали объект класса Person(firstName, lastName, age, phoneNumber) со случайными значениями полей с использованием faker и с использованием instancio:
🔴Faker
Faker faker = Faker.instance();
Person person = new Person();
person.setFirstName(faker.name().firstName());
person.setLastName(faker.name().lastName());
person.setAge(faker.number().randomDigit());
person.setPhoneNumber(faker.phoneNumber().phoneNumber());
🔵Instancio
Person person = Instancio.create(Person.class);
Конечно не обойдется без нюансов. По умолчанию Instancio будет заполнять поля объекта полностью рандомными данными, в то время как с Faker мы будем получать данные, более похожие на реальные, живые. Для примера - как будут выглядеть объекты Person, сгенерированные двумя способами выше:
Person{firstName='Haydee', lastName='Kertzmann', age=4, phoneNumber='067.506.7057'} //для fakerPerson{firstName='HRDYGWQP', lastName='UYEOXLEO', age=8229, phoneNumber='BBCCSDU'} //для instancioНо каждому инструменту - свое применение. Резюмирая: Faker - про генерацию фейковых данных (но реалистично выглядящих). Instancio - про создание объектов, с полями, забитыми случайными данными (что может быть более актуально в unit-тестировании).
Саму зависимость Instancio можно найти здесь: https://mvnrepository.com/artifact/org.instancio/instancio
Дополнительно почитать про возможности и настройку библиотеки - тут: https://www.instancio.org/user-guide/#creating-objects (боже храни людей которые пишут документацию).
👍6🔥3❤1
Что на картинке? Монитор центра управления полетами на Байконуре?🚀
Упс, это вкладка Performance в Chrome DevTools. По сути - история процесса построения и отрисовки страницы.
Сегодня заглянем во внутрянку как браузер превращает прилетевший текст HTML, CSS, JS - в сочную картинку. Упрощенно, шаги такие:
1. сборка DOM-дерева на базе HTML - строим объекты на базе каждого узла.
2. сборка CSSOM-дерева на базе CSS - строим объекты на базе каждого правила.
3. Render Tree - сборка дерева рендеринга. По сути это применение стилей к объектам DOM, т.е. объединение DOM + CSSOM
4. Layout - расчет размеров элементов, их расположения и взаимного размещения.
5. Paint - подготовка и прорисовка моделей элементов в растровые картинки.
6. Compositing - группировка полученных картинок в слои и отображение этих слоев на экран.
И еще - мы взаимодействуем со страницей, а не просто любуемся. Поэтому тык на любую кнопку может привести к перерисовке страницы и повторению всех шагов выше.
Так что тыкайте кнопки экономно, берегите ваш CPU😜
Упс, это вкладка Performance в Chrome DevTools. По сути - история процесса построения и отрисовки страницы.
Сегодня заглянем во внутрянку как браузер превращает прилетевший текст HTML, CSS, JS - в сочную картинку. Упрощенно, шаги такие:
1. сборка DOM-дерева на базе HTML - строим объекты на базе каждого узла.
2. сборка CSSOM-дерева на базе CSS - строим объекты на базе каждого правила.
3. Render Tree - сборка дерева рендеринга. По сути это применение стилей к объектам DOM, т.е. объединение DOM + CSSOM
4. Layout - расчет размеров элементов, их расположения и взаимного размещения.
5. Paint - подготовка и прорисовка моделей элементов в растровые картинки.
6. Compositing - группировка полученных картинок в слои и отображение этих слоев на экран.
И еще - мы взаимодействуем со страницей, а не просто любуемся. Поэтому тык на любую кнопку может привести к перерисовке страницы и повторению всех шагов выше.
Так что тыкайте кнопки экономно, берегите ваш CPU😜
1🔥8❤1👍1
🔥3
Подъехали сладкие темы!🍪🍭🍫
Cookie (печенька, кука) - кусочек информации, которую бразузер получает от сервера, и дальше передает при любом запросе к этому серверу. Например, сервер может пользуется куками что бы пометить нас как конкретного пользователя и в дальнейшем узнавать, и даже что-то помнить о нас. Типа как дал кликуху во дворе.
Очень упрощенно, кука содержит:
1. Данные - имя свойства и его значение. В терминах Java можно думать об этом как о строковой переменной у которой есть имя и значения.
2. Адрес сайта к которому эта кука относится
3. Срок действия куки
Что может храниться в куки? Да любая дичь😄 Это просто строка в которой могут быть любые символы. Но самые частые кейсы данных в куки такие:
- 🧑кто ты такой (может хранить session id, токен, или еще какой удостоверяющий документ)
- ⚙️какие настройки сайта используешь (язык, светлая/темная тема)
- 📝какое состояние сайта у тебя сейчас (например в корзине покупок лежит три шерстяных носка)
Жми 🔥 что бы разжечь пожар, в котором родится видос с подробным разбором темы😉
Cookie (печенька, кука) - кусочек информации, которую бразузер получает от сервера, и дальше передает при любом запросе к этому серверу. Например, сервер может пользуется куками что бы пометить нас как конкретного пользователя и в дальнейшем узнавать, и даже что-то помнить о нас. Типа как дал кликуху во дворе.
Очень упрощенно, кука содержит:
1. Данные - имя свойства и его значение. В терминах Java можно думать об этом как о строковой переменной у которой есть имя и значения.
2. Адрес сайта к которому эта кука относится
3. Срок действия куки
Что может храниться в куки? Да любая дичь😄 Это просто строка в которой могут быть любые символы. Но самые частые кейсы данных в куки такие:
- 🧑кто ты такой (может хранить session id, токен, или еще какой удостоверяющий документ)
- ⚙️какие настройки сайта используешь (язык, светлая/темная тема)
- 📝какое состояние сайта у тебя сейчас (например в корзине покупок лежит три шерстяных носка)
Жми 🔥 что бы разжечь пожар, в котором родится видос с подробным разбором темы😉
🔥17👍2
🔺Люди с древних времен обожают строить пирамиды - пирамида Хеопса, пирамида Маслоу, пирамида тестирования. Сегодня о последней - как протестировать код автотестов? Ведь никаких API и UI слоев там нет.
Компилятор - первый рубеж обороны. Мы забываем про этот уровень проверок, но именно компилятор спасает прод от самых глупых и частых ошибок - когда ругает нас за отсутствие ';' или за присвоение переменной неправильного типа данных. Т.е. - тут же отфутболивает нерабочий код.
Статический анализ - находит баги, антипаттерны, проблемы со стилем кода. Пример - встроенные проверки Intellij IDEA - подсветка нескольких идентичных копипастнутых фрагментов кода, или потенциально бесконечного цикла. Эти проверки можно настроить под себя. А можно подключить Checkstyle-плагин и написать свои собственные. Об этом в отдельном посте.
Юнит-тесты на автотестовый фреймворк - важно, но не всегда оправданно. В сложных больших фреймах - нужны. В остальных случаях - считай экономику, считай как часто ты меняешь важные/нагруженные классы проекта, как часто там возникают ошибки. Важно ответить себе - стоит ли овчинка выделки.
В итоге как бы ни выглядела пирамида, ее золотое правило одинаково:
Чем быстрее (ниже по уровню пирамиды) найдена ошибка - тем дешевле ее устранить.
Компилятор - первый рубеж обороны. Мы забываем про этот уровень проверок, но именно компилятор спасает прод от самых глупых и частых ошибок - когда ругает нас за отсутствие ';' или за присвоение переменной неправильного типа данных. Т.е. - тут же отфутболивает нерабочий код.
Статический анализ - находит баги, антипаттерны, проблемы со стилем кода. Пример - встроенные проверки Intellij IDEA - подсветка нескольких идентичных копипастнутых фрагментов кода, или потенциально бесконечного цикла. Эти проверки можно настроить под себя. А можно подключить Checkstyle-плагин и написать свои собственные. Об этом в отдельном посте.
Юнит-тесты на автотестовый фреймворк - важно, но не всегда оправданно. В сложных больших фреймах - нужны. В остальных случаях - считай экономику, считай как часто ты меняешь важные/нагруженные классы проекта, как часто там возникают ошибки. Важно ответить себе - стоит ли овчинка выделки.
В итоге как бы ни выглядела пирамида, ее золотое правило одинаково:
Чем быстрее (ниже по уровню пирамиды) найдена ошибка - тем дешевле ее устранить.
🔥9👍3❤1
- Нееет, ты не можешь описать различия между абстрактным классом и интерфейсом одной картинкой!
- Могу, если на ней будет текст😄
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3😁2🙏1
Про работу Maven с локальным и удаленным репозиторием.
Все то же самое что на картинке - но языком аналогий.
Представь что ты готовишь кесадилью (ага, открываем сезон мексиканских блюд).
И по рецепту (pom.xml) для твоего Проекта Кесадилья тебе нужны ингредиенты - зависимости:
Где их искать? Можно порыться у себя в холодильнике (❄️локальный репозиторий). А если в холодильнике нет сыра? Идем за сыром в супермаркет (🛒удаленный репозиторий).
И приготовив кесадилью - остатки - например сыр - мы кладем обратно в холодильник, т.е. он у нас остается про запас в ❄️локальном репозитории.
Прелесть библиотеки в том что она не испортится в холодильнике (❄️локальном репозитории) и не закончится - ее для сборок можно использовать сколько угодно раз. И если она есть у нас локально - в сеть за ней мы уже не пойдем.
Т.е. в отличии от реального мира - в мире Maven достаточно "купить" сыр один раз что бы он всегда был и никогда не закончился🥲🥲🥲*звуки зависти
Все то же самое что на картинке - но языком аналогий.
Представь что ты готовишь кесадилью (ага, открываем сезон мексиканских блюд).
И по рецепту (pom.xml) для твоего Проекта Кесадилья тебе нужны ингредиенты - зависимости:
<dependencies>
<dependency>🌮тортилья</dependency>
<dependency>🧀сыр</dependency>
<dependency>🥩мясо</dependency>
<dependency>🍅помидор</dependency>
<dependency>🧅лук</dependency>
<dependency>🌶перец</dependency>
</dependencies>
Где их искать? Можно порыться у себя в холодильнике (❄️локальный репозиторий). А если в холодильнике нет сыра? Идем за сыром в супермаркет (🛒удаленный репозиторий).
И приготовив кесадилью - остатки - например сыр - мы кладем обратно в холодильник, т.е. он у нас остается про запас в ❄️локальном репозитории.
Прелесть библиотеки в том что она не испортится в холодильнике (❄️локальном репозитории) и не закончится - ее для сборок можно использовать сколько угодно раз. И если она есть у нас локально - в сеть за ней мы уже не пойдем.
Т.е. в отличии от реального мира - в мире Maven достаточно "купить" сыр один раз что бы он всегда был и никогда не закончился🥲🥲🥲*звуки зависти
🔥8👍6❤1😁1
"Что лежит в его мерзких грязных карманцах?"
(с) Голлум, Властелин колец
Пороемся в карманах у браузера - где и что он хранит - и разберем cookies, sessionStorage & localStorage.
Про куки мы уже говорили в одном из постов выше. Вкратце - это небольшие файлы, которые сервер подкладывает в наш браузер что бы помнить кто ты, что ты, и какие настройки используешь. Куки отправляются сайту с каждым запросом к этому сайту.
📦localStorage - долгосрочное хранилище данных. Данные из localStorage доступны из любого окна/вкладки и хранятся до тех пор пока ты сам или веб приложение их не удалит. Т.е. localStorage похож на браузерный кеш - только хранит не скрипты, стили и картинки - а данные.
🖼Пример из жизни - Youtube хранит уровень громкости видео в localStorage (по ключу yt-player-volume), а раз localStorage доступен для всех вкладок и окон - то поэтому по умолчанию каждое новое открытое окно ютюба будет иметь одинаково выставленный уровень громкости.
🔒Доступ - через DevTools (вкладка Application) или через JS:
localStorage.setItem('имяКлюча', 'значение'); //запись
localStorage.getItem('имяКлюча'); //чтение📦sessionStorage - временное хранилище данных. Данные хранятся только пока ты находишься на конкретном сайте в конкретной вкладке. Как только ты покинешь сайт или закроешь вкладку - пиши пропало. Это типа буфера обмена, или временных заметок на полях для веб-приложений.
🖼Пример из жизни - Amazon при оформлении заказа может хранить данные из заполненных форм именно тут - что бы если пользаку после заполнения адреса доставки вдруг приспичило вернуться на предыдущий шаг - данные уже заполненного адреса не оказались потеряны. А Netflix - сохранит в sessionStorage текущую отметку времени просмотра видоса, так что при обновлении страницы ты не упадешь в самое начало серии а продолжишь просмотр оттуда где прервался. А еще с помощью sessionStorage запомнит что показывал те или иные рекомендации что бы не бесить по 10 раз подряд всплывашкой с рекомендацией одного и того же сериала.
🔒Доступ - через DevTools (вкладка Application) или через JS:
sessionStorage.setItem('имяКлюча', 'значение'); //запись
sessionStorage.getItem('имяКлюча'); //чтениеВ основе sessionStorage & localStorage так же как и у кук - лежит доменная модель. Т.е. каждому сайту - свой огород, свое пространство. Поэтому не удивляйся когда увидишь во вкладке дев тулов Local storage и Session storage по несколько хранилищ каждого из типов - каждый из сайтов будет иметь свое и в то же время не будет иметь доступа к "чужим" хранилищам, хранилищам других сайтов.
📦Для особо тяжелых (ресурсоемких) случаев - есть еще и IndexedDB - встроенная в браузер база данных (присутствует и в Chrome, и в Firefox, и в Safari). Там размер не фиксирован 5 или 10 мегабайтами и может достигать до 20% от свободного дискового пространства, а иногда и больше.
🖼Пример из жизни - та же гугл почта или гугл доки будут хранить копию данных в indexedDB, что позволит продолжить с ними работу даже при потере интернет-соединения. А при возврате коннекта - локально внесенные изменения в indexedDB тут же подтянутся на сервер, в облако.
___
P.S. огоньки🔥, сердечки❤️ и репосты📩 очень помогают каналу и заряжают мою батарейку на дальнейшее творчество и контент😉😇
4🔥16❤6👍1🙏1
