Че там в React 19
У меня сейчас, к сожалению или к счастью, нет времени полностью посмотреть React Conf, которая длится аж 4 часа, что имхо очень много.
Я пролистал конфу и нашёл пару интересных моментов, которыми хочу поделиться тут.
Как я понял, React Compiler — это что-то, что стоит сравнивать скорее с компилятором TypeScript. Также один из спикеров сравнивает его с компиляторами типа WebAssembly и Hermes, который сейчас используется в React Native. По сути, всё, что он делает — разбирает весь ваш код и представляет его в виде полностью контролируемого графа. Сам по себе компилятор содержит очень много оптимизаций, типа автоматического удаления неиспользуемого кода, распространения констант и ещё куча умных слов. Все эти техники оптимизации не новы, но спикеры подмечают, что, конечно же, подсосали всё из Rust и C++, что не удивительно.
Цель такого компилятора — дополнительно оптимизировать весь наш код без видимых изменений для разработчика, тем самым улучшить и DX, и UX.
Что наиболее интересно — компилятор приносит нам такое интересное понятие как Computation Graph. Как я понимаю, это понятие мы ещё не раз услышим в будущем.
Computation Graph — граф, который отображает вычислительные зависимости между сущностями в коде. Показывает то, каким образом данные влияют на другие данные и на вёрстку в целом. Что-то типа
Тут обращаем внимание на скрины. Со 2 по 6 мы видим то, что такое Computation Graph и как он получается из нашего кода. На 7 скрине мы видим как это работает. Из полученного графа мы можем узнать минимально нужный перечень сущностей для обновления, то есть что конкретно мы хотим обновить, при этом не затрагивая остальные несвязанные ветви графа.
Во что конкретно компилятор собирает это — я пока не досмотрел. Но даже эта ограниченная информация — очень интересно)
@prog_way_blog — чат — #theory #react #news
У меня сейчас, к сожалению или к счастью, нет времени полностью посмотреть React Conf, которая длится аж 4 часа, что имхо очень много.
Я пролистал конфу и нашёл пару интересных моментов, которыми хочу поделиться тут.
Как я понял, React Compiler — это что-то, что стоит сравнивать скорее с компилятором TypeScript. Также один из спикеров сравнивает его с компиляторами типа WebAssembly и Hermes, который сейчас используется в React Native. По сути, всё, что он делает — разбирает весь ваш код и представляет его в виде полностью контролируемого графа. Сам по себе компилятор содержит очень много оптимизаций, типа автоматического удаления неиспользуемого кода, распространения констант и ещё куча умных слов. Все эти техники оптимизации не новы, но спикеры подмечают, что, конечно же, подсосали всё из Rust и C++, что не удивительно.
Цель такого компилятора — дополнительно оптимизировать весь наш код без видимых изменений для разработчика, тем самым улучшить и DX, и UX.
Что наиболее интересно — компилятор приносит нам такое интересное понятие как Computation Graph. Как я понимаю, это понятие мы ещё не раз услышим в будущем.
Computation Graph — граф, который отображает вычислительные зависимости между сущностями в коде. Показывает то, каким образом данные влияют на другие данные и на вёрстку в целом. Что-то типа
useMemo
и других хуков, когда мы напрямую указывали реакту, изменение чего конкретно нужно отслеживать и что конкретно нужно пересчитать. Теперь этим полностью занимается компилятор. Тут обращаем внимание на скрины. Со 2 по 6 мы видим то, что такое Computation Graph и как он получается из нашего кода. На 7 скрине мы видим как это работает. Из полученного графа мы можем узнать минимально нужный перечень сущностей для обновления, то есть что конкретно мы хотим обновить, при этом не затрагивая остальные несвязанные ветви графа.
Во что конкретно компилятор собирает это — я пока не досмотрел. Но даже эта ограниченная информация — очень интересно)
@prog_way_blog — чат — #theory #react #news
👍24❤5🔥2🤯1🐳1
Какие ошибки есть в JavaScirpt?
Уже не помню где, скорее всего в чате канала, просили разобрать какие есть ошибки в языке. Вот и этот пост.
Что вообще такое ошибка? Ошибка — ответ программы на возможное неожиданное, некорректное поведение. Всего в JavaScript существует всего 7 встроенных ошибок, но также есть возможность создавать собственные, что я уже разбирал в отдельном посте ранее.
Также важно знать, что в языке есть встроенная конструкция
Этой вводной должно быть достаточно, перейдём к самим ошибкам:
Как вы можете видеть, ошибок очень мало. Последние три встречаются так редко, что их буквально можно не учитывать. Практически любая библиотека или фреймворк предоставляют собственный набор ошибок, поэтому придётся обращать внимание и на них. К счастью, большинство из них имеют достаточно подробное описание уже в самой консоли.
Пост вдохновлён статьей с доки
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript
Уже не помню где, скорее всего в чате канала, просили разобрать какие есть ошибки в языке. Вот и этот пост.
Что вообще такое ошибка? Ошибка — ответ программы на возможное неожиданное, некорректное поведение. Всего в JavaScript существует всего 7 встроенных ошибок, но также есть возможность создавать собственные, что я уже разбирал в отдельном посте ранее.
Также важно знать, что в языке есть встроенная конструкция
try {
// потенциально ошибочный код
} catch (error) {
// обработка ошибки из
// участка кода выше
}
Этой вводной должно быть достаточно, перейдём к самим ошибкам:
SyntaxError
— ошибка, связанная с некорректным синтаксисом в программе, то есть некорректной, постановкой скобок, точек с запятой и прочих символов:console.log(()
// Uncaught SyntaxError: Unexpected token ')'
Reference Error
— возникает при попытке обратиться к несуществующей переменнойprogway.length
// ReferenceError: progway is not defined
Type Error
— возникает при попытке обратиться к несуществующему свойству объекта или попытке вызвать то, что вызвать нельзяconsole.log(null.length)
// TypeError: Cannot read property 'length' of null
undefined()
// TypeError: undefined is not a function
Range Error
— возникает, когда мы выходим за диапазон допустимых значенийnew Array(10_000_000_000)
// RangeError: Недопустимая длина массива
URIError
— возникает при некорректной обработке URI встроенными средствами языкаdecodeURIComponent('%')
// URIError: URI malformed
Eval Error
— по сути, любая вышеперечисленная ошибка внутри функции eval
eval('progway.length')
Как вы можете видеть, ошибок очень мало. Последние три встречаются так редко, что их буквально можно не учитывать. Практически любая библиотека или фреймворк предоставляют собственный набор ошибок, поэтому придётся обращать внимание и на них. К счастью, большинство из них имеют достаточно подробное описание уже в самой консоли.
Пост вдохновлён статьей с доки
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript
🔥20👍9❤4🐳1🤓1
В чём разница между функцией, методом и процедурой
Функция и метод — это два базовых понятия в программировании, но они используются в разных контекстах.
1. Функция — полностью независимый блок, который может быть объявлен где угодно в коде. Каждая функция возвращает значение и может принимать аргументы:
2. Процедура — то же самое, что и функция, но процедура лишь выполняет какие-то действия, но ничего не возвращает:
3. Метод — то же самое, что функция или процедура, но принадлежащая определенному объекту или классу. Всегда вызывается от родительской сущности через точечную нотацию:
Принципиально ли использовать правильные названия для каждого из случаев? Для такого душнилы, как я, — да. Я считаю, что верная терминология делает любой разговор более продуктивным и предметным, чем “ну вот это фигня там вот с этой фигней”. Понять друг друга можно и без терминологии, но с ней — гораздо проще. Да и звучите вы профессиональнее, если это для кого-то важно.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript
Функция и метод — это два базовых понятия в программировании, но они используются в разных контекстах.
1. Функция — полностью независимый блок, который может быть объявлен где угодно в коде. Каждая функция возвращает значение и может принимать аргументы:
// самая настоящая функция, причём чистая
function add(a, b) {
return a + b;
}
2. Процедура — то же самое, что и функция, но процедура лишь выполняет какие-то действия, но ничего не возвращает:
// что-то делаем, но ничего не возвращаем
function greet(name) {
console.log("Hello, " + name);
}
3. Метод — то же самое, что функция или процедура, но принадлежащая определенному объекту или классу. Всегда вызывается от родительской сущности через точечную нотацию:
let obj = {
x: 4,
// метод
double: function() {
return this.x * 2;
}
};
let result = obj.double();
console.log(result); // Выведет: 8
Принципиально ли использовать правильные названия для каждого из случаев? Для такого душнилы, как я, — да. Я считаю, что верная терминология делает любой разговор более продуктивным и предметным, чем “ну вот это фигня там вот с этой фигней”. Понять друг друга можно и без терминологии, но с ней — гораздо проще. Да и звучите вы профессиональнее, если это для кого-то важно.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript
🔥33👍17❤5👏1🐳1
Семантическое версионирование
Способ создавать человекочитаемые наглядные номера версий для любого продукта. Для версионирования используется единый шаблон:
1. Мажорные версии (major): Увеличиваются, когда вносятся несовместимые изменения API.
2. Минорные версии (minor): Увеличиваются, когда добавляются новые функции, сохраняя обратную совместимость.
3. Патч-версии (patch): Увеличиваются, когда выпускаются исправления ошибок, сохраняя обратную и прямую совместимость.
4. Предрелизные версии (preRelease): Можно добавлять к номеру версии суффиксы, чтобы обозначить предварительные версии (например, alpha, beta, rc).
Примеры:
Кстати, обычно суффиксы встречаются такие:
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #useful
Способ создавать человекочитаемые наглядные номера версий для любого продукта. Для версионирования используется единый шаблон:
<major>.<minor>.<patch>-<preRelease>
1. Мажорные версии (major): Увеличиваются, когда вносятся несовместимые изменения API.
2. Минорные версии (minor): Увеличиваются, когда добавляются новые функции, сохраняя обратную совместимость.
3. Патч-версии (patch): Увеличиваются, когда выпускаются исправления ошибок, сохраняя обратную и прямую совместимость.
4. Предрелизные версии (preRelease): Можно добавлять к номеру версии суффиксы, чтобы обозначить предварительные версии (например, alpha, beta, rc).
Примеры:
1.0.0
1.2.3
2.0.0
1.5.0-alpha.1
1.5.0-rc.2
4.2.1-snapshot.4
5.18.2-test.1
Кстати, обычно суффиксы встречаются такие:
1. dev
— версия, которая может содержать изменения, находящиеся в процессе разработки, и не является полностью стабильной2. alpha
— первая версия программного продукта, которая обычно имеет ограниченный набор функций и может содержать много ошибок3. beta
— версия, которая следует за альфа-версией и обычно уже более стабильна. В бета-версию могут быть добавлены новые функции, но она все еще может содержать некоторые ошибки4. release-candidate (rc)
— версия, которая считается готовой к выпуску, но перед официальным релизом требует дополнительного тестирования и обратной связи от пользователей5. preview
— версия, которая предварительно показывает новые функции или изменения, которые будут включены в будущую версию6. test
— версия, которая используется для тестирования новых функций или исправлений перед их включением в основную ветку разработкиСпасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #useful
❤19👍8🔥6🤔1🐳1
Хочется создать очень ламповое и приятное место для общения на основе канала
В чатике можно задать абсолютно любой вопрос, предложить тему для поста, поделиться переживаниями и просто познакомиться с единомышленниками
Обязательно присоединяйтесь, приглашайте друзей — давайте общаться
@prog_way_blog — чат — #blog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥3🐳3💯1
Что такое мемоизация
Мемоизация — техника оптимизации кода, сокращающая время его исполнения.
Представим, что у нас есть функция
1. Вызовем функцию, подождём 10 секунд и сохраним результат её выполнения в кэш
2. Вызовем функцию ещё раз с теми же аргументами. Вместо того, чтобы исполнять тяжелый код, обратимся к кэшу и проверим нет ли там нужного для нас результат вычислений
3. Если нужный результат есть, вернём его. Если нет, см. шаг 1
Любую ли функцию можно мемоизировать? Конечно же нет. Мемоизировать можно только чистые функции. О том, что это такое, я писал отдельный пост.
Также стоит учитывать, что со временем жизни программы кэш может очень сильно разрастись. Из-за этого сама программа может занимать очень много памяти. Решением может быть несколько подходов:
1. Установить время жизни для каждого из значение кэша
2. Подход LRU (Last Recently Used), когда мы удаляем из кэша значения, которые дольше всего не запрашивались. Такой подход позволяет сохранять в кэше только самые часто используемые данные.
3. Ограничение размера кэша, то есть, когда кэш достигает порогового значения по количеству записей или памяти, старые записи удаляются для освобождения места под новые
4. Просто удалять весь кэш по какому-то таймауту
Сложность тут в том, что нам необходимо реализовать собственный кэш с поддержкой всех необходимых апи для того, что мы описали выше. В JavaScript, например, LRU кэша из коробки, то есть его придётся написать самостоятельно. Самая примитивная же форма кэша для мемоизации, которая и используется чаще всего —
Если нет желания писать свой велосипед, что прекрасно, можно использовать готовые реализации, например, из библиотеки
В следующем посте рассмотрим реализацию примитивной мемоизации в коде.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #patterns #data
Мемоизация — техника оптимизации кода, сокращающая время его исполнения.
Представим, что у нас есть функция
foo
, которая выполняется 10 секунд. Нам нужно вызвать эту функцию 3 раза подряд с одними и теми же аргументами. Несложно посчитать, что такой код будет выполняться 30 секунд. Но мы можем применить мемоизацию:1. Вызовем функцию, подождём 10 секунд и сохраним результат её выполнения в кэш
2. Вызовем функцию ещё раз с теми же аргументами. Вместо того, чтобы исполнять тяжелый код, обратимся к кэшу и проверим нет ли там нужного для нас результат вычислений
3. Если нужный результат есть, вернём его. Если нет, см. шаг 1
Любую ли функцию можно мемоизировать? Конечно же нет. Мемоизировать можно только чистые функции. О том, что это такое, я писал отдельный пост.
Также стоит учитывать, что со временем жизни программы кэш может очень сильно разрастись. Из-за этого сама программа может занимать очень много памяти. Решением может быть несколько подходов:
1. Установить время жизни для каждого из значение кэша
2. Подход LRU (Last Recently Used), когда мы удаляем из кэша значения, которые дольше всего не запрашивались. Такой подход позволяет сохранять в кэше только самые часто используемые данные.
3. Ограничение размера кэша, то есть, когда кэш достигает порогового значения по количеству записей или памяти, старые записи удаляются для освобождения места под новые
4. Просто удалять весь кэш по какому-то таймауту
Сложность тут в том, что нам необходимо реализовать собственный кэш с поддержкой всех необходимых апи для того, что мы описали выше. В JavaScript, например, LRU кэша из коробки, то есть его придётся написать самостоятельно. Самая примитивная же форма кэша для мемоизации, которая и используется чаще всего —
Map
или же обычный объект.Если нет желания писать свой велосипед, что прекрасно, можно использовать готовые реализации, например, из библиотеки
lodash
— вот исходники функцииВ следующем посте рассмотрим реализацию примитивной мемоизации в коде.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #javascript #patterns #data
👍30🐳5🔥4❤2
Что будет в консоли?
Anonymous Quiz
78%
1, false, true
7%
false, NaN, false
9%
false, false, true
6%
0, true, true
🐳9
progway — программирование, IT
Не забудьте присоединиться
Реально годнота же🤷♂️ 🤷♂️ 🤷♂️
Реально годнота же
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳5😁3🤩2
Реализация мемоизации в JavaScript
О том, что такое мемоизация, я рассказывал в прошлом посте.
На самом деле, всё это довольно просто. Попробуем написать функцию-обёртку
Наша функция-обёртка будет принимать только целевую функцию, которую мы хотим мемоизировать. В качестве кэша будем использовать
И далее просто воспользуемся замыканием, чтобы ограничить доступ к созданному кэшу только для целевой функции. Для этого вернем из
Полный код функции:
Я осознанно не использовал TypeScript, так как он сильно визуально усложняет эту функцию и объяснений получается много. Натыкайте 🔥 на пост и я разберу как правильно типизировать такую функцию
@prog_way_blog — чат — #theory #code #javascript #data
О том, что такое мемоизация, я рассказывал в прошлом посте.
На самом деле, всё это довольно просто. Попробуем написать функцию-обёртку
memoize
, с помощью которой можно мемоизировать любую другую функцию. Начнём как всегда с интерфейса:function memoize(func) {
// ...
}
Наша функция-обёртка будет принимать только целевую функцию, которую мы хотим мемоизировать. В качестве кэша будем использовать
Map
:const cache = new Map();
И далее просто воспользуемся замыканием, чтобы ограничить доступ к созданному кэшу только для целевой функции. Для этого вернем из
memoize
новую функцию:return function(...args) {
// ключ сериализуем в строку, чтобы
// не было проблем с аргументами
// объектами, массивами и т.д.
const key = JSON.stringify(args);
// проверяем есть ли результат в кэше
if (!cache.has(key)) {
// если нет, то сохраняем в кэш
// значение вызова функции
cache.set(key, func(...args));
}
// и возвращаем значение из кэша
return cache.get(key);
};
Полный код функции:
function memoize(func) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, func(...args));
}
return cache.get(key);
};
}
Я осознанно не использовал TypeScript, так как он сильно визуально усложняет эту функцию и объяснений получается много. Натыкайте 🔥 на пост и я разберу как правильно типизировать такую функцию
@prog_way_blog — чат — #theory #code #javascript #data
🔥76👍5🐳2❤1😁1
const car = {
size: 'small'
};
const box = {
type: 'mailbox',
small: true
};
@prog_way_blog — чат — #quiz
👍5🐳2
При выполнении какого кода будет ошибка? И будет ли?
Anonymous Quiz
47%
box.car.size
11%
box[car.size]
12%
box[car["size"]]
31%
Ошибки не будет
🔥12🤯12🐳2👍1
Как типизировать функцию мемоизации
В прошлом посте я разбирал реализацию функции мемоизации на JavaScript и упомянул, что типов там нет осознанно. В этом посте мы отдельно разберём типизацию такой функции, это будет полный разбор для самых маленьких.
Шпаргалка по используемым в посте utility-типам:
Итак, наша функция принимает в себя другую функцию. Сразу же типизируем это:
Далее было бы неплохо типизировать возвращаемую функцию. Для этого мы можем использовать следующую конструкцию:
И итоговый интерфейс функции у нас сильно растянется, но будет таким:
Ребята, стараюсь максимально упростить. Если плохо понимаете дженерики, постарайтесь более внимательно вчитываться в код.
Далее типизация кэша, тут всё просто:
По типизации, ключ — строка, а значение — тот тип, который возвращает оригинальная функция.
Далее рассмотрим итоговый код:
Надеюсь вышло понятно. Если что, любые вопросы можем обсудить в комментариях.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #typescript
В прошлом посте я разбирал реализацию функции мемоизации на JavaScript и упомянул, что типов там нет осознанно. В этом посте мы отдельно разберём типизацию такой функции, это будет полный разбор для самых маленьких.
Шпаргалка по используемым в посте utility-типам:
Parameters<T> - возвращает тип аргументов функции T
ReturnType<T> - возвращает тип возвращаемых значений функции T
const foo = (a: number , b: number) => 5
type Args = Parameters<typeof foo>
// [a: number, b: number]
type Return = ReturnType<typeof foo>
// number
Итак, наша функция принимает в себя другую функцию. Сразу же типизируем это:
function memoize(func: (...args: any[]) => any) {
// ...
}
Далее было бы неплохо типизировать возвращаемую функцию. Для этого мы можем использовать следующую конструкцию:
(...args: Parameters<оригинальная функция>) => ReturnType<оригинальная функция>
. И вот мы сталкиваемся с проблемой, что для корректной типизации возвращаемой функции нам необходимы типы Parameters
и ReturnType
, которые обязательно принимают дженерик. В качестве дженерика выступает тип оригинальной функции. Для удобства вынесем тип оригинальной функции в дженерик функции memoize
:function memoize<T extends (...args: any[]) => any>(func: T) {
// ...
}
И итоговый интерфейс функции у нас сильно растянется, но будет таким:
type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>
function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
// ...
}
Ребята, стараюсь максимально упростить. Если плохо понимаете дженерики, постарайтесь более внимательно вчитываться в код.
Далее типизация кэша, тут всё просто:
const cache = new Map<string, ReturnType<T>>();
По типизации, ключ — строка, а значение — тот тип, который возвращает оригинальная функция.
Далее рассмотрим итоговый код:
type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>
function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
const cache = new Map<string, ReturnType<T>>();
return function(...args: Parameters<T>): ReturnType<T> {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, func(...args));
}
return cache.get(key)!;
};
}
Надеюсь вышло понятно. Если что, любые вопросы можем обсудить в комментариях.
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #code #typescript
🔥24👍6🤯3❤2🐳1
Обработка сочетания клавиш в JavaScript
Чтобы обработать сочетание клавиш, необходимо подписаться на событие
Для примера возьмём сложное сочетание клавиш:
Но тут стоит учитывать, что
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
Чтобы обработать сочетание клавиш, необходимо подписаться на событие
keydown
. В большинстве случаев вы будете подписываться на document
, если сочетание клавиш глобальное по всему приложению.Для примера возьмём сложное сочетание клавиш:
command(alt) + shift + U
document.addEventListener('keydown', function(event) {
if (event.metaKey && event.shiftKey && event.key === 'U') {
// че-то делаем на нажатие
}
});
Но тут стоит учитывать, что
metaKey
в разных браузерах работает по разному, в том числе могут быть проблемы в Safari. Самым безопасным вариантом будет следующий код:document.addEventListener('keydown', function(event) {
const isApple = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
if ((isApple && event.metaKey && event.shiftKey && event.key === 'U') ||
(!isApple && event.altKey && event.shiftKey && event.key === 'U')) {
// че-то делаем на нажатие
}
});
Спасибо за прочтение, это важно для меня ❤️
@prog_way_blog — чат — #theory #code #javascript
👍47❤10🤯4🔥3🐳3🌚2