Геймификация в охране труда: кому, зачем и как? | Веб-студия Nat.od.ua
Геймификация в охране труда: кому, зачем и как?
Часто бывает так, что обучение, проводимое работодателем, сводится просто к формальности. Сотруднику дают несколько страниц текста или несколько часов видео и потом проверяют его знания с помощью теста, где нужно просто отметить правильный ответ. Однако опыт специалистов в области охраны труда показывает, что такие методы неэффективны и не способствуют достижению основных целей этой области – сохранению здоровья и жизни сотрудников.
Использование геймификации может быть полезным для бизнеса, а игры могут помочь сотрудникам эффективнее учиться и снижать количество травм внутри компании.
Читать далее
Как добавить несколько товаров в Shopify корзину одним кликом? / Хабр | Веб-студия Nat.od.ua
Как добавить несколько товаров в Shopify корзину одним кликом? / Хабр
Недавно я писал конфигуратор в Shopify и решил поделиться тем, как добавить несколько товаров в Шопифай корзину. Я находил не так много материалов по этому вопросу, тем более на русском языке.
Прикрепляю скринкаст того, что можно сделать при помощи этого. Но применений довольно много, не только конфигуратор. В скринкасте я добавил 6 товаров по одному клику на “Add to cart” кнопку. Но до лимита в количестве добавляемых товаров я не дошёл, может их и нет.
Cart API
Чтобы добавить в корзину несколько товаров, вам необходимо отправить в Cart API объект items с идентификатором(id) продукта и количеством(quantities) товара. На скриншоте ниже я добавляю один товар по клику.
Подготовка items объекта для API
Но обязательно отправляйте идентификатор продукта вместо идентификатора варианта, если у вашего продукта есть варианты, иначе будет ошибка.
Так должен выглядеть отправляемый объект:
items:
Пример того, как можно сделать fetch запрос. Это не самая сложная версия такого запроса, но и не самая простая.
document.querySelectorAll(“form.configurator-form”).forEach((form) => {
form.addEventListener(“submit”, async (e) => {
e.preventDefault();
// Показываем спиннер загрузки
const loadingOverlays = document.querySelectorAll(“.loading-overlay”);
loadingOverlays.forEach((overlay) => overlay.classList.remove(“hidden”));
// Собираем данные товаров
const productData = selectedProducts.map((product) => ({
id: product.id,
quantity: 1,
variantId:
product.variantId && product.variantId !== product.id
? parseInt(product.variantId)
: undefined,
}));
const requestBody = {
items: productData,
};
// Добавляем товары в корзину
await fetch(`${window.Shopify.routes.root}cart/add.js`, {
method: “POST”,
headers: {
“Content-Type”: “application/json”,
},
body: JSON.stringify(requestBody),
});
// Обновляем корзину
const res = await fetch(“/cart.json”);
const cart = await res.json();
// Обновляем число на корзине
document.querySelectorAll(“.cart-count-bubble”).forEach((el) => {
el.textContent = cart.item_count;
});
// Перенаправляем пользователя на страницу корзины
window.location.href = “https://habr.com/cart”;
});
});Заключение
Будьте внимательны когда перед вами встанет эта задача, там довольно много подводных камней. Например, если у товара нет вариантов, то ID в value нужно передавать вот так:
{{ product.selected_or_first_available_variant.id }}
Полный код передаваемого инпута будет выглядеть так:
Но если варианты есть, то уже так:
{{ product.id }}
Полный код похож на предыдущий input, просто value другое:
Вот такой небольшой трюк, который вы теперь знаете. И ещё теперь вы умеете добавлять в корзину несколько товаров. Хорошей разработки!
Прогресс WebAssembly и будущее веба. Быстрые интерфейсы, пример Figma / Хабр | Веб-студия Nat.od.ua
Прогресс WebAssembly и будущее веба. Быстрые интерфейсы, пример Figma / Хабр
WebAssembly (Wasm) — это бинарный формат для безопасного и эффективного выполнения портативных программ в стековой виртуальной машине (в браузере или на сервере). Как и ASM.js, представляет собой низкоуровневый код. Есть ещё WAT — WebAssembly Text, человекочитаемая версия бинарного кода.
WebAssembly — не столько язык программирования, сколько цель компиляции, новый вид ассемблера, который работает близко к железу, принимая программы на C, C++, Rust и других привычных языках. При этом Wasm гораздо быстрее ASM.js и выполняет код в браузере почти как нативные программы под любой ОС.
Анатомия модуля WebAssembly. Программы называются модулями, потому что здесь нет разницы между программой и библиотекой, источник
Первая версия набора функций WebAssembly 1.0 одобрена консорциумом W3С, а некоторые стандартные фичи уже поставлены во все ведущие браузеры. Даже есть случаи масштабного рефакторинга на Wasm, после которого производительность сайта по некоторым параметрам возрастает в несколько раз.
Формат Wasm разработан для того, чтобы браузер мог как можно быстрее его разобрать. Например, вот время загрузки модулей Figma до и после оптимизации:
И код Wasm очень компактен, так что сетевая задержка тоже минимизируется до предела. Сравнение размера до и после оптимизации:
Такая разница в размере неудивительна, потому что синтаксис JavaScript был разработан для людей и содержит много избыточности и дополнительных правил, которые необходимо проверить перед выполнением.
До появления WebAssembly код C++ можно было выполнять в браузере путём кросс-компиляции на Asm.js. Это подмножество JavaScript, в котором можно использовать только числа (никаких строк, объектов и т. д.). Для C++ ничего больше не нужно, поскольку здесь всё является либо числом, либо указателем на число (а указатели — это тоже числа). Адресное пространство C++ — это просто гигантский массив чисел JavaScript, а указатели — просто индексы в этом массиве.
WebAssembly работает иначе, и поэтому здесь перед выполнением не нужно проверять код на ограничения JavaScript/Asm.js. В итоге бинарный код WebAssembly декодируется и выполняется иногда в 23 раза быстрее, чем соответствующий код asm.js.
Другие преимущества Wasm:
- Код C++ сильно оптимизируется компиляторами LLVM ещё до перевода в WebAssembly. Это значит, что браузер может напрямую транслировать его в нативный код, без всяких оптимизаций. В отличие от Wasm, обычный JS для быстродействия нужно оптимизировать на многих уровнях.
- Для браузеров не составляет труда кэшировать трансляцию модуля Wasm в нативный код. То есть при второй загрузке страница с этим модулем запускается практически мгновенно. Этого нельзя сказать об Asm.js, который смешивается с обычным JavaScript и требует сложной проверки, что он действительно соответствует требованиям.
- WebAssembly нативно поддерживает 64-битные целые. В JavaScript поддерживаются 64-битные флоаты (с плавающей запятой) и только 53-битные целые. 64-битные приходится эмулировать, что гораздо медленнее.
▍ Высокая производительность
Можно найти великолепные примеры высокой производительности веб-приложений. Например,
форумный движок AsmBB
, написанный полностью на WebAssembly, с интерфейсом FastCGI и базой SQLite для хранения зашифрованных данных. Целью разработки было создание максимально быстрого и лёгкого движка, при этом с современным UI. Насколько это получилось, можно оценить на
asmbb.org
.
Проект собран компилятором Flat Assembler (FASM). Размер движка около 65 КБ. За счёт минимального размера он всегда в самом быстром серверном кэше. Это уменьшает задержку, создавая ощущение высокой скорости. Разница заметна в том случае, если сеть и БД не являются узкими местами при обращении к серверу. В противном случае, конечно, всё равно, на чём написан сам движок. Тут происходит оптимизация конкретно CPU на сервере, ведь форумы с высокой посещаемостью на самом деле неслабо нагружают процессор. AsmBB запускается абсолютно на любом сервере x86, даже стареньком домашнем ПК. Возможно, это самый быстрый в мире форумный движок (такие бенчмарки ещё не попадались).
Инструкция по установке:
Или взять графический веб-редактор
Figma
, который в 2018 году осуществил
масштабный рефакторинг
, переписав ключевые части движка на Webasm. Это позволило
в несколько раз ускорить ключевые операции
. Например, загрузка документов ускорилась в три раза:
Эту оптимизацию пришлось проводить после того, как редактор Figma начали использовать корпоративные менеджеры для создания сверхсложных приложений. Например, дизайнеры из группы Fluent Design Team в Microsoft создали единый документ Figma со
всеми элементами управления Windows
во всех возможных состояниях и перестановках. По отдельности это несложные вычисления, но время загрузки такого документа оказалось существенным. Оптимизация на Webasm позволила сократить его с 29 до 8 с.
Чтобы понимать сложность обработки в редакторе, некоторые файлы Figma с сотнями тысяч слоёв с трудом умещаются в браузерный лимит оперативной памяти 2 ГБ для кучи. Из браузеров лимит 4 ГБ поддерживает только Chrome, да и то с багами.
На WebAssembly переписали все части, где происходит взаимодействие приложения с пользователями, включая десктопные версии, Chrome, Firefox и Safari на macOS и Windows.
Масштабирование тоже стало втрое быстрее:
Перетаскивание мышкой до и после оптимизации WebAssembly:
Если эти операции выполняются без лагов (фреймы максимальной длины в сотни миллисекунд), то в анимациях UI выпадает меньше кадров. Figma ориентируется на комфортный для пользователя фреймрейт 60 fps без лагов. К этому показателю приложение напрямую приблизилось после оптимизации WebAssembly:
Быстрый интерфейс — неотъемлемая часть удобного UX.
Для людей, которые устали от тормозных интерфейсов ожиревших сайтов и неповоротливых приложений, примеры использования WebAssembly с отзывчивым UI — словно глоток свежего воздуха в атмосфере современного веба.
Figma стала одним из пионеров по внедрению Wasm, потому что сооснователь и технический директор (ведущий программист) Figma Эван Уоллес был большим фанатом WebAssembly и опенсорса. Он выкладывал свои разработки на Github и многое сделал для продвижения этого революционного веб-стандарта (уволился в 2021-м).
Figma до сих пор остаётся примером не только коммерческого успеха, но и технического совершенства как программное приложение. Хотя сейчас появилось уже много последователей, веб-редакторов для быстрого прототипирования интерфейсов, таких как Penpot.
Penpot▍ Изучение WebAsm на практике
Для интенсивного изучения
WAT
с глубоким погружением можно рекомендовать
WATlings
— это специальный курс обучения путём исправления маленьких программ. Опыт показывает, что новые навыки усваиваются максимально быстро, если сразу дать практические задания, то есть создать «препятствия», которые ученик будет
самостоятельно
преодолевать. Это самая эффективная методика.
Многое о языке можно узнать только из его синтаксиса. Возникающие пробелы в знаниях восполняются знакомством с синтаксисом в различных контекстах. То есть многие вещи усваиваются без всякого предварительного объяснения, а просто на практике.
Здесь ещё один наглядный пример того, что излишние объяснения не только затрудняют, но и замедляют понимание предмета. Бывает, что годичный курс теории вполне заменяется трёхмесячной практикой. Об этом методе подготовки много хороших отзывов, так что его стоит попробовать.
Похожий подход обучения программированию с помощью задач использует Exercism, а курс по WebAssemly включает 21 упражнение.
Exercism
Но там учиться сложнее. Придётся читать много теоретического материала, который даётся параллельно.
Другие примеры кода на WAT для изучения см. здесь.
▍ Будущее — за WebAssemly
Подводя итог, WebAssemly позволяет создавать в веб-приложения, которые по производительности не уступают нативным программам для настольных компьютеров. Это новая универсальная вычислительная платформа. Она уже доказала свои преимущества для C, C++, Rust и других языков, а теперь сообщество WebAsm
готово к покорению мира
. Игра началась.
P. S. Как мы уже говорили, многие функции WebAssembly 1.0 приняты и поддерживаются браузерами. В ближайшие месяцы ожидается внедрение в браузеры ключевой поддержки GC, после чего Wasm сможет ссылаться и обращаться к JavaScript, DOM и общим объектам, определяемым WebIDL. Также идёт разработка новых функций, входящих в набор следующего поколения WebAssembly 2.0.
Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх 🕹️
Знакомство с рунами / Хабр | Веб-студия Nat.od.ua
Знакомство с рунами / Хабр
Эта статья — перевод оригинальной статьи “Introducing runes”.
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
В 2019 году Svelte 3 превратил JavaScript в реактивный язык. Svelte – это фреймворк для создания веб-интерфейса, который использует компилятор для превращения декларативного кода компонентов в такой…
…в жестко оптимизированный JavaScript, который обновляет документ при изменении состояния, например, count. Поскольку компилятор “видит”, где ссылаются на count, генерируемый код очень эффективен, а поскольку мы используем такие синтаксисы, как let и =, а не громоздкие API, вы можете писать меньше кода.
Чаще всего мы получаем такие отзывы: “Хотел бы я писать весь свой JavaScript именно так”. Когда вы привыкли к тому, что вещи внутри компонентов волшебным образом обновляются, возврат к старому скучному процедурному коду кажется вам переходом от цветного к черно-белому.
В Svelte 5 все это изменилось благодаря рунам, которые открывают универсальную, тонкую реактивность.
Прежде чем начать
Несмотря на то, что мы меняем принцип работы под капотом, Svelte 5 должен стать полноценной заменой практически для всех. Новые возможности являются опциональными – существующие компоненты будут продолжать работать.
Дата выхода Svelte 5 пока не определена. То, что мы показываем здесь, – это наработки, которые, могут измениться.
Что такое руны?
Руны – это символы, влияющие на работу компилятора Svelte. Если сегодня в Svelte для обозначения конкретных вещей используются let, =, ключевое слово export и метка $:, то руны используют синтаксис функций для достижения того же и даже большего.
Например, чтобы объявить часть реактивного состояния, мы можем использовать руну $state:
На первый взгляд, это может показаться шагом назад – возможно, даже не по-свельтовски. Не лучше ли, если let count будет реактивным по умолчанию?
Нет. Реальность такова, что по мере роста сложности приложений выяснение того, какие значения являются реактивными, а какие нет, может стать сложной задачей. К тому же эвристика работает только для объявлений let на верхнем уровне компонента, что может привести к путанице. Если в файлах .svelte код ведет себя одним образом, а в .js – другим, это может затруднить рефакторинг кода, например, если вам нужно превратить что-то в хранилище, чтобы использовать его в нескольких местах.
За пределами компонентов
С помощью рун реактивность выходит за пределы файлов .svelte. Предположим, мы хотим инкапсулировать логику счетчика таким образом, чтобы ее можно было повторно использовать в разных компонентах. Сегодня для этого используется кастомное хранилище в файле .js или .ts:
import { writable } from ‘svelte/store’;
export function createCounter() {
const { subscribe, update } = writable(0);
return {
subscribe,
increment: () => update((n) => n + 1)
};
}
Поскольку в данном случае реализуется контракт с хранилищем – возвращаемое значение имеет метод subscribe, – мы можем ссылаться на значение магазина, добавляя к его имени префикс $:
//
Это работает, но довольно странно! Мы обнаружили, что API хранилища может стать довольно громоздким, когда вы начинаете делать более сложные вещи.
С рунами все гораздо проще:
// import { writable } from ‘svelte/store’;
export function createCounter() {
// const { subscribe, update } = writable(0);
let count = $state(0);
return {
// subscribe,
// increment: () => update((n) => n + 1)
get count() { return count },
increment: () => count += 1
};
}
// clicks: {$counter}
clicks: {counter.count}
Обратите внимание, что мы используем свойство get в возвращаемом объекте, поэтому counter.count всегда ссылается на текущее значение, а не на значение в момент вызова функции.
Реактивность во время выполнения
Сегодня Svelte использует реактивность во время компиляции. Это означает, что если у вас есть код, использующий метку $: для автоматического перезапуска при изменении зависимостей, то эти зависимости будут определены при компиляции компонента в Svelte:
Это работает хорошо… до того момента пока не перестанет. Предположим, что мы рефакторим приведенный выше код:
const multiplyByHeight = (width) => width * height;
$: area = multiplyByHeight(width);
Поскольку объявление $: area = … может “видеть” только width, оно не будет пересчитываться при изменении height. В результате код трудно рефакторить, а понимание тонкостей того, когда Svelte решает обновить те или иные значения, может стать довольно сложным после определенного уровня сложности.
В Svelte 5 появились руны $derived и $effect, которые вместо этого определяют зависимости своих выражений при их вычислении:
Как и $state, $derived и $effect также могут быть использованы в файлах .js и .ts.
Усиление сигнала
Как и любой другой фреймворк, мы пришли к пониманию того, что Knockout всегда был прав.
Реактивность Svelte 5 обеспечивается сигналами, которые, по сути, являются тем, чем занимался Knockout в 2010 году. Совсем недавно сигналы были популяризированы Solid и приняты множеством других фреймворков.
Однако у нас все немного по-другому. В Svelte 5 сигналы – это детали реализации, а не то, с чем вы взаимодействуете напрямую. Таким образом, мы не имеем тех же ограничений на дизайн API и можем максимально повысить эффективность и эргономичность. Например, мы избегаем проблем с сужением типов, возникающих при обращении к значениям через вызов функции, а при компиляции в режиме рендеринга на стороне сервера мы можем вообще отказаться от сигналов, поскольку на сервере они – не более чем накладные расходы.
Сигналы позволяют реализовать мелкозернистую реактивность, то есть, например, изменение значения в большом списке не обязательно должно приводить к аннулированию всех остальных членов списка. Таким образом, Svelte 5 работает невероятно быстро.
Впереди более простые времена
Руны – это добавочное свойство, но они делают устаревшими целую кучу существующих концепций:
разница между let на верхнем уровне компонента и в остальных местах
export let
$:, со всеми вытекающими отсюда странностями
разное поведение между
TypeScript и все что тебе нужно в разработке / Хабр | Веб-студия Nat.od.ua
TypeScript и все что тебе нужно в разработке / Хабр
Автор: Маслов Андрей, Front-end разработчик.
О статье
Эта статья создана для облегчения процесса изучения TypeScript с помощью практичных примеров. Более подробную информацию можно найти в документации или в дополнительных материалах.
Статья предназначена как для начинающих разработчиков, которые только начинают знакомиться с TypeScript, так и для опытных разработчиков, желающих углубить свои знания в этом языке. Здесь вы найдете краткое и информативное изложение ключевых аспектов TypeScript, которые могут быть полезными в повседневной разработке. Для вашего удобства, оглавление статьи содержит ссылки на конкретные темы TypeScript, так что вы можете быстро перейти к интересующей вас части материала.
НавигаторIntersection Types и Union TypesIntersection Types
В TS вы можете пересекать типы. Вы можете получить тип C способом пересечения типов А и В. Смотрите пример ниже:
type A = {
id: number
firstName: string
lastName: string
}
type B = {
id: number
height: number
weight: number
}
type C = A & B
//Итог пересечения типов A и B
type C = {
id: number
firstName: string
lastName: string
height: number
weight: number
}Union Types
Аналогично пересечению, вы можете выполнить и объединение типов, т.е создать аннотации несколько типов в текущей переменной. Смотрите пример ниже:
type A = number
type B = string
type C = A | B
//Итог объединения A и B
type C = number или string
const parseAmount = (val: C) => {
if (typeof val === ‘number’) {
return val
}
if (typeof val === ‘string’) {
return val.resplace(‘,’, ‘.’)
}
}Generic Types
Дженерики значительно расширяют возможности TypeScript в повседневном программировании, позволяя нам эффективно переиспользовать типы, избегая создания множества аналогичных “клонов”. Давайте рассмотрим это на практическом примере: создание типа, способного корректно обрабатывать ответы методов.
type FetchResponse
data: T
errorMessage: string
errorCode: number
}
type AuthDataRs = {
accessToken: string
refreshToken: string
}
const login = async (lg: string, ps: string): FetchResponse
const response = await fetch(…)
return response
}
//FetchResponse
//переиспользовать FetchResponse для различных запросов.
При необходимости можно расширять свой тип несколькими дженериками:
type FetchResponse
data: T
error: P
}
Так же вы можете назначать тип по умолчанию дженерику:
type FetchResponse
data: T
error: P
}
Если дженерику не назначен явный тип по умолчанию, то вам необходимо обязательно указывать тип при его использовании. В случае, если у дженерика есть дефолтное значение, передача типа может быть опциональной или даже вовсе не требоваться.
Utility Types
Это утилиты, которые предназначены для удобной работы, а именно генерации новых типов на основе других.
Awaited
Awaited
Утилита предназначена для ожидания в асинхронных операциях, например:
type A = Awaited
//type A -> numberPartial
Partial
Утилита предназначена для создания нового типа, где каждое свойство станет опциональным. Напомню, для того чтобы сделать свойство объекта опциональным, необходимо использовать знак “?”:
type A = {
id: number
name?: string //Опциональное свойство (необязательное)
}
Как работает Partial ?
type A = {
id: number
name: string
}
//Output
type B = {
id?: number //Опциональное свойство (необязательное)
name?: number //Опциональное свойство (необязательное)
}Required
Required
Утилита работает в точности наоборот как Partial. Свойства текущего типа делает строго обязательными.
type A = {
id?: number
name?: string
}
//Output
type B = {
id: number //Обязательное свойство
name: number //Обязательное свойство
}Readonly
Readonly
Утилиты преобразует все свойства типа, делает их недоступными для переназначения с использованием нового значения.
type A = {
id: number
name: string
}
const firstObj: A = { id: 0, name: ‘first’}
const secondObj: B = { id: 1, name: ‘second’}
firstObj.name=”first_1″ // it’s correct
secondObj.name=”second_2″ //Cannot assign to ‘name’ because it is a read-only property.
Если у вас есть необходимость сделать поле readonly только для определенного свойства объекта, то необходимо написать ключевое слово перед именем св-ва:
type A = {
readonly id: number
name: string
}Record
Record
Утилита предназначена для создания типа объекта, Record
enum CarNames {
AUDI = ‘audi’,
BMW = ‘bmw’
}
type CarInfo = {
color: string
price: number
}
type Cars = Record
//Output
type Cars = {
audi: CarInfo;
bmw: CarInfo;
}Pick
Pick
Утилита предназначена для создания нового типа из выбранных свойств объекта.
type A = {
id: number
name: string
}
//Output 1
type B = {
name: string
}
//Output 2
type B = {
id: number
name: string
}Omit
Omit
Утилита предназначена для создания типа из оставшихся (не исключенных) свойств объекта.
type A = {
id: number
name: string
}
//Output 1
type B = {
name: string
}
//Output 2
type B2 = {}Exclude
Exclude
Утилита создает тип, исключая свойства, которые уже присутствуют в двух разных типах. Он исключает из T все поля, которые можно назначить U.
type A = {
id: number
name: string
length: number
}
type B = {
id: number
color: string
depth: string
}
type C = Exclude
//Output
type C = {
name: string
length: number
}Extract
Extract
Создает тип, извлекая из T все члены объединения, которые можно назначить U.
type A = {
id: number
name: string
length: number
}
type B = {
id: number
name: string
color: string
depth: string
}
type C = Extract
//Output
type C = {
id: number
name: string
}ReturnType
ReturnType
Создает тип, состоящий из типа, возвращаемого функцией T.
type A = () => string
//Output
type B = string
Это одни из основных Utility Types, в материалах к статье я оставлю ссылку на документацию, где при желании вы сможете разобрать остальные утилиты для продвинутой работы с TS.
Conditional Types
В TypeScript есть возможность создавать типы в зависимости от передаваемого дженерика.
type ObjProps = {
id: number
name: string
}
type ExtendsObj
const obj1: ObjProps = {
id: 0,
name: ‘zero’
}
const obj2 = {
id: 1
}
type A = ExtendsObj
type B = ExtendsObj
Сопоставленные типы позволяют вам взять существующую модель и преобразовать каждое из ее свойств в новый тип.
type MapToNumber
: number
}
const obj = {id: 0, depth: ‘1005’}
type A = MapToNumber
//Output
type A = {
id: number
depth: number
}Type Guards
Если тип не определен или неизвестен, то на помощь разработчику приходит “защита типов”.
typeof
Самый простой способ обезопасить себя от ошибки, напрямую проверить тип при помощи оператора typeof (ранее в примерах вы могли видеть использование этого оператора, который возвращает тип переменной).
const fn = (val: number | string) => {
if (typeof val === ‘number’) {
return …
}
throw new Error(`Тип ${typeof val} не может быть обработан`)
}in
Еще один из способов защитить тип, использовать in, этот оператор проверяет присутствие свойства в объекте.
const obj = {
id: 1,
name: ‘first’
}
const bool1 = ‘name’ in obj //true
const bool2 = ‘foo’ in obj //falseinstanceof
Оператор экземпляра проверяет, появляется ли свойство прототипа конструктора где-нибудь в цепочке прототипов объекта
function C() {}
function D() {}
const o = new C();
o instanceof C //true
o instanceof D //falseis
Этот оператор указывает TypeScript какой тип присвоить переменной, если функция возвращает true. В примере ниже оператор is сужает тип у переменной foo (string | number) до string. Это определенная пользователем защита типа. Благодаря защите компилятор приводит тип до определенного внутри блока if.
interface FirstName {
firstName: string
}
interface FullName extends FirstName {
lastName: string
}
const isFirstName = (obj: any): obj is FirstName => {
return obj && typeof obj.firstName === “string”
}
const isFullName = (obj: any): obj is FullName => {
return isFirstName(obj) && typeof (obj as any).lastName === “string”;
}
const testFn = (objInfo: FirstName | FullName | number) => {
if (isFullName(objInfo)) {
console.log(‘Тип FullName’)
} else if (isFirstName(objInfo)) {
console.log(‘Тип FirstName’)
} else {
console.log(‘Тип не принадлежит FullName или FirstName’)
}
}
testFn({ firstName: ‘Andrey’ }) //Тип FirstName
testFn({ firstName: ‘Andrey’, lastName: ‘Maslov’ }) //Тип FullName
testFn(1) //Тип не принадлежит FullName или FirstNameЗаключение
Как видите, TypeScript – это мощный инструмент для разработки, который позволяет улучшить качество вашего кода, сделать его более надежным и легко поддерживаемым. В этом туториале мы рассмотрели приемы работы с TypeScript, над такими продвинутыми темами, например, как дженерики и type guards.
Не забывайте, что изучение TypeScript – это постоянный процесс, и чем больше вы практикуетесь, тем более уверенно будете использовать его в своих проектах.
Если у вас возникнут вопросы или потребуется дополнительная помощь, обращайтесь к официальной документации TypeScript или дополнительным материалам.
Материалы для изучения
Основы
Utility Types
Шпаргалка по TS в картинках
Sinuous — JavaScript UI библиотека с небольшим размером / Хабр | Веб-студия Nat.od.ua
Sinuous — JavaScript UI библиотека с небольшим размером / Хабр
Есть много библиотек и фреймворков, которые помогают преодолеть все препятствия на пути JavaScript разработчика. Если раньше мы использовали ванильный JS, то со временем пришёл jQuery, а затем React и Vue. Каждый год появляется все больше новых библиотек, фреймворков и инструментов. Некоторые из них продолжают развиваться и находят свою аудиторию, в то время как другие исчезают и постепенно забываются. В статье рассмотрим ещё одну библиотеку, которая может быть полезной для разработки небольших и простых пользовательских интерфейсов.
Что это вообще?
Sinuous — быстрая реактивная UI библиотека. Sinuous начинался как небольшой эксперимент, чтобы добиться такого же поведения, как Surplus , но с литералами шаблонов вместо JSX.
Размер Sinuous составляет всего 1.4kB. Это делает её идеальной для встраивания в HTML-страницу, компоненты или виджеты. Одна из целей — сохранить простоту Javascript. Поэтому в библиотеке очень мало специализированного синтаксиса. Если разрабатывается что-то действительно большое и сложное, несомненно стоит брать React/Vue.
Sinouse не использует VDOM в классическом смысле. Есть лишь map модуль, который делает что-то похожее. Для динамических частей Sinuous использует простой Observable , который обеспечивает обновления указанные в представлении. Иными словами, оцениваются лишь те части, которые изменяются, без необходимости сравнивать всё DOM-дерево.
Sinuous предоставляет template надстройку, которая может предварительно отображать повторяющиеся фрагменты HTML.
Вот ссылка на репозиторий Sinous на GitHub.
Установка
Sinuous доступен в NPM для использования с упаковщиком модулей или в приложении Node:
npm install sinuousПростой компонент
Простой пример библиотеки, не требующий особых пояснений:
import { html } from ‘sinuous’;
const HelloMessage = ({ name }) => html`
`;
document.querySelector(‘.hello-example’).append(
html`<${HelloMessage} name=World />`
);
Единственное, что здесь следует отметить, что html тег скомпилирован для h вызова функций библиотекой HTM . Это можно сделать либо во время выполнения, либо во время сборки.
Компонент с сохранением состояния
Помимо получения входных данных через props, также поддерживается внутреннее состояние компонента, доступ к которому происходит через observables. При изменении данных состояния компонента, отображаемая разметка будет автоматически обновляться путём повторного вызова необходимых операций с DOM.
import { o, html } from ‘sinuous’;
const Timer = (props) => {
const seconds = o(0);
function tick() {
seconds(seconds() + 1);
}
setInterval(tick, 1000);
return html`
`;
};
document.querySelector(‘.counter-example’).append(
html`<${Timer}/>`
);Простая тудушка
Функция o создаёт наблюдаемую переменную, которая может содержать любое значение, которое нужно сделать реактивным в представлении. Вызывая эту функцию без аргумента, она действует как метод получения значения; если передаётся аргумент, она устанавливает новое значение наблюдаемой переменной.
При первом рендеринге Sinuous обнаружит все использованные наблюдаемые переменные и выполнит соответствующие операции с DOM, сохранённые ранее. Если новому значению будет присвоена наблюдаемая переменная, она просто выполнит ранее сохранённые операции с DOM, используя новое значение.
import { o, html } from ‘sinuous’;
import { map } from ‘sinuous/map’;
const TodoApp = () => {
let items = o([]);
let text = o(”);
const view = html`
TODO
<${TodoList} items=${items} />
`;
function handleSubmit(e) {
e.preventDefault();
if (!text().length) {
return;
}
const newItem = {
text: text(),
id: Date.now()
};
items(items().concat(newItem));
text(”);
}
function handleChange(e) {
text(e.target.value);
}
return view;
};
const TodoList = ({ items }) => {
return html`
- ${item.text}
${map(items, (item) => html`
`)}
`;
};
document.querySelector(‘.todos-example’).append(TodoApp());В итоге
Sinuous простая и лёгкая библиотека, которая включает в себя работу с компонентами, состоянием, рендирингом, списками, гидратацией, шаблонами и наблюдателям. Её можно использовать для создания каких-то небольших виджетов или приложений.
API для создания рандомных аватаров пользователей / Хабр | Веб-студия Nat.od.ua
API для создания рандомных аватаров пользователей / Хабр
Аватарки популярны на многих сайтах и позволяют украсить профиль не используя свою реальную фотографию. В статье рассмотрим простые и доступные API для генерации аватарок на свой сайт.
UI Avatars
UI Avatars — простой API для создания аватарок с инициалами имён. Нужно просто написать имя или фамилию. Дополнительно можно задать фон, цвет букв, размер шрифта, жирность текста, формат изображения SVG или PNG и многое другое. Данное API можно использовать как запасной вариант Gravatar.
DiceBear
DiceBear — помимо рандомных аватаров формата SVG, позволяет создавать детерминированные аватарки для идентификаторов пользователей. Встроенный PRNG создаёт один и тот же аватар на основе начального числа. Примеры использования: JavaScript, HTTP API, CLI , плагин Figma, Editor и Playground.
RoboHash
RoboHash — довольно интересный API, позволяет генерировать аватарки роботов, пришельцев и монстров. Изображения создаются в форматах JPG, PNG и bitmap. Введите любой текст, например IP-адрес, email, имя файла, идентификатор пользователя или что-то ещё, и получите красивое изображение для своего сайта.
Multiavatar API
Multiavatar API — содержит более 12 млрд уникальных мультикультурных аватаров. Изображения генерируются на основе имён в форматах SVG и PNG. Ограничение API для пользователей без аккаунта составляет 10 вызовов в минуту. Доступны пакеты на PHP, Python, JavaScript и Solidity.
Если вам известны другие API для генерации аватаров, делитесь ими в комментариях!
5 советов разработчику перед стартом своего стартапа. Опыт после 750 000 рублей / Хабр | Веб-студия Nat.od.ua
5 советов разработчику перед стартом своего стартапа. Опыт после 750 000 рублей / Хабр
Всем привет! Меня зовут Ростислав, я full-stack разработчик. Последние 3 года у меня есть хобби – доведение пет-проектов до стадии финансово рентабельных IT продуктов. Сейчас я хочу поделиться своими советами о запуске проекта, исходя из своего опыта.
Если имеет значение: раньше я разрабатывал на React и NestJS, сейчас перешёл на React и FastAPI (Python).
Сейчас у меня есть два проекта, приносящих прибыль:
Telegram чат для сайта (Telegram Feedback) – ~40 000 руб / мес.
Доступ к ChatGPT (ChatGPT Me) – ~70 000 руб / мес.
P.S. Если интересно посмотреть – ссылки в закрепленном комментарии.
Суммарно они принесли мне ~750к выручки за последние полтора года (но практически всё ушло в реинвест):
Минутка пруфов
Следовательно, что-то у меня получилось. Пусть и немного, но заставить проекты работать не в минус – довольно большое достижение.
Еще штук 5 проектов я похоронил на разных этапах развития, поэтому негативного опыта у меня тоже достаточно (и он в чем-то даже более ценный).
Перейдём к сути: допустим, вы разработчик, выбрали идею и решили воплотить её в продукт с целью заработать. Вот мои советы:
1. Не думайте, что разработка – это всё, что нужно для успеха
Несколько лет назад я думал: сейчас сделаю классный полезный продукт и у меня буду пользователи! Но нет. Так не работает.
Разработка – это не самая большая сложность. Как правило, что-то разработать вообще не проблема, это только решаемая задача (тем более для программиста).
Проблема в другом.
Какой бы классный у вас продукт не был, никто им не будет пользоваться, если не узнает о нем.
Если пользователь узнает о продукте – может не зарегистрироваться. Если зарегистрируется – может не оплатить. Если оплатил – может уйти.
Заставить аудиторию узнать о продукте во время такого информационного шума сложно и дорого. Удержать внимание попроще, но тоже тяжело. Все компании сейчас борются за внимание аудитории.
И именно эта задача будет у вас основной и самой сложной. Заранее приготовьтесь к тому, что основная борьба за успех продукта будет не на поле разработки.
Но это не означает, что разработкой не нужно заниматься. Она будет занимать очень большое количество времени, просто это не будет самым сложным.
Разумеется, есть исключение: если вы придумали прорывную технологию по типу ChatGPT. Но для этого вам нужны хотя бы сотни миллионов долларов, так что такой вариант не рассматриваем.
2. Концентрируйтесь на маркетинге и постоянно учитесь новому. Это самое важное
Если вы решили заниматься продуктом самостоятельно, продвигать вам его тоже самостоятельно. Придется научиться. Я вот до конца так и не научился, но активно пытаюсь.
Какие-то источники продвижения у вас будут основными, какие-то желательно просто держать в голове.
Вот мой субъективный “начальный” список тем, которые нужно знать хотя бы поверхностно перед запуском своего продукта. Уточню: везде своя специфика, я говорю только про свой опыт.
1) Что такое SEO и как с ним работать
SEO – самый дешёвый источник регистраций, если вы смогли добиться каких-то позиций в поиске. Но обычно это игра или в долгосрочную, или для нового рынка (на какое-то время у меня сработало с ChatGPT).
Разберитесь как:
делать правильную структуру сайта;
попадать в хорошие показатели Google Page Speed;
как закупать ссылки (и мой совет: покупайте только вечные).
Полезные ссылки:
Для проверки производительности сайта – https://pagespeed.web.dev/.
Базовый чек-лист – https://backlinko.com/seo-checklist.
Любые другие материалы по SEO, их тонны.
Бонус для разработчиков: если вы умеете в вёрстку и SSR – вам будет легче с SEO.
2) Как изучать ЦА и выявлять боли
IT продукт – это не про функции, а про решение болей конечного пользователя
Полезные ресурсы:
В целом книг по маркетингу и продажам много, все не вспомню, но я читал и изучал очень многое. Чем больше изучите, тем лучше. Умение понять свою ЦА – это база.
Важный момент: маркетинг – это всё-таки практический навык. Поэтому нужно практиковаться и пробовать, иначе ваши знания не пригодятся.
3) Навык настраивать Яндекс Директ
По моему опыту, через этот источник легче всего привлекать первых пользователей. Реклама легко настраивается, стоит не очень дорого, научиться достаточно легко.
Правда слить бюджет тоже очень легко.
Полезные ресурсы:
любое видео на YouTube на 1-2 часа (например, вот);
официальная документация.
Главное: старайтесь всегда настраивать рекламу через конверсии.
4) Минимальный навык настройки аналитики
Яндекс Метрика вам в помощь.
Что нужно уметь понимать:
сколько человек к вам заходят;
из каких источников;
сколько регистраций;
сколько реальных пользователей;
сколько платящих пользователей;
на каких этапах пользователи отваливаются.
Аналогично советую посмотреть вводные видео на YouTube длиной от часа. И изучайте официальную документацию.
5) Базовые навыки дизайна
Продукт должен быть удобным и понятным. В идеале, красивым, но этот пункт в самом начале точно можно опустить.
Поэтому нужно понимать, как структурировать информацию на сайте, на текущем экране и максимально понятно доносить до пользователя полезность.
Полезные ресурсы:
большое кол-во бесплатных и платных курсов – https://www.uprock.ru/;
насмотренность на Behance и Dripple.
Желательно пройти курсы по UX’y. Но я не проходил и посоветовать не могу. До этого момента я просто смотрел в аналитику по конверсиям и думал “как улучшить этот шаг”.
6) Умение работать с конструктором сайтов
В самом начале нужно будет очень много тестировать гипотезы продаж. На каждый чих верстать сайт долго.
Поэтому нужно уметь быстро собирать сайты на каком-нибудь конструкторе.
Для себя я выбрал Tilda, т.к. это достаточно простой конструктор и выдает достаточно быстрые SEO-совместимые сайты (с некоторыми оговорками). Говорят, Creatium тоже неплохой.
3. В самом начале – попытайтесь продать макет продукта
Этот момент для меня был довольно неочевидным. Я сначала брался за разработку и пытался показать пользователям хотя бы MVP. Иногда в MVP была даже интегрирована платежная система!
Оказалось, это частенько было лишним.
Для понимания, что разработку не стоит даже начинать и продукт никому не интересен (или вы выбрали не ту ЦА) достаточно следующего:
Сделать лендинг на конструкторе, который будет вести на форму регистрации.
Сделать форму регистрации.
Пустить рекламу на сайт через Яндекс Директ или закупить на подходящем ресурсе (Telegram, YouTube и т.д.).
Посчитать стоимость регистрации.
И умножить эту стоимость на 3, чтобы приблизить её к теоретически реальной. Регистрация – это ещё не конечный пользователь, который будет пользоваться вашим продуктом и, тем более, платить.
Посмотреть, готовы ли вы продолжать с такой стоимостью пользователя.
Минус для разработчиков: из разработки тут только форма регистрации. Всё остальное – это маркетинг.
4. Делайте максимально просто и быстро
Опять из своего опыта: перед запуском и в первое время после запуска проектов я старался добавить всевозможные функции, которые могут пригодиться пользователям.
Делал качественно, периодически покрывал тестами и продумывал все наперед (а как это будет работать, если будет 100 000 пользователей).
И… так делать не нужно до тех пор, пока продукт не станет рентабельным. Просто потому, что 80% функций вы или выкинете, или ими не будут пользоваться.
Самая выгодная стратегия: сделать максимально просто, лишь бы работало. Умеренно забить на качество и расширяемость. И идти дальше добавлять функции, которые просят пользователи.
Качеством и масштабированием займетесь, когда продукт будет окупаться и когда у вас появится время на “стабилизацию” ситуации. Или вообще не займётесь, потому что это не нужно.
Это тот случай, когда “недобдеть” экономически более целесообразно, чем “перебдеть”.
5. Привыкните к синдрому самозванца
Когда вы занимаетесь разработкой своего проекта, вы неизбежно сталкиваетесь с очень широким спектром задач:
от верстки лендинга до установки даундетектора;
от оптимизации конверсии в регистрацию до резервного копирования БД;
от сбора обратной связи до интеграции с платежными системами.
Тут вы должны быть фуллстеком, тут скорее программисто-маркетолого-продактом придется быть.
Примерно половину своих задач вы будете делать в лучшем случае не совсем плохо или, если повезёт, нормально. Просто потому, что на всё нет времени и нельзя быть сильным специалистом во всем.
Это абсолютно нормально. Так и нужно делать. Пусть не везде качественно, пусть не везде хорошо, но лучше работающий хоть как-то продукт, который приносит пользу, чем идеально продуманная идея
По мере необходимости будете улучшать стабильность и дорабатывать функционал, дизайн и продажи. Или звать людей в команду для этих задач
Но до стабильной прибыли разрабатывайте необходимый минимум, максимально просто и не парьтесь о будущем (которого может и не быть, хе-хе).
Вывод
Процесс создания своего IT продукта – это долгий процесс, который требует широкого спектра знаний и навыков.
С первой попытки ничего не получится, со второй выйдет плохо. Но по мере попыток – может и выйдет действительно полезный продукт, который найдет свою аудиторию.
Напомню, что у меня есть серия статей про развитие своего проекта – “Стартап в соло. Часть 1: текущие показатели”
—
И поставьте лайк, пожалуйста. Мне это действительно важно ❤
Минуты и часы не нужны / Хабр | Веб-студия Nat.od.ua
Минуты и часы не нужны / Хабр
landing page для наглядности
Вступление 1
Эта статья модификация прошлой статьи двухлетней давности:
https://habr.com/ru/articles/569410/
В той статье я излагал свои мысли, получил кучу критики и в итоге многое переосмыслил. Там я в целом описывал ряд изменений связанных со временем (недели, месяцы, часовые пояса, часы, минуты и секунду). Но сейчас я понимаю, что с практической точки зрения, реализация тех идей не рациональна. И поэтому я сократил свое кардинально. Из всех изменений я оставил только два пункта. И в этой статье я постараюсь максимально вас переубедить почему эта идея реально имеет смысл. И в чем заключается эта концепция.
Мое приложение
beresta.app (play market)
Я написал своё приложение, в котором я полностью реализовал данную концепцию. И после того, как вы прочитаете эту статью, я призываю вас переходить на мою сторону и тоже реализовывать эту концепцию. Она подойдет практически везде. Так как мы повсеместно используем время всюду.
Я открыт для любых предложений и коллаборации. Просто пишите мне в лс, если хотите помочь продвижению данной концепции. Примеры вашей помощи я напишу в самом низу (но вы можете придумать и свои), если будет желание, я всегда рад прорекламировать вас также.
Начнём
Наверняка вы когда-то задумывались, почему время измеряется в часах и минутах? И действительно, посмотрите на большинство единиц измерения, если мы измеряем в больших количествах, мы просто обрезаем по три нуля, и добавляем приставки кило-, мега-, гига- и т.д. И это намного разумнее. То есть каждая более крупная единица равняется 1000 мелким. Зачем делать более крупную единицу равную 60 мелким.
Ответ очень простой. На мой взгляд, это сложилось исторически. Просто какой-то один человек очень давно подумал, что это будет удобно так измерять время, но нет. Кроме того что у нас получается красивое число 24 часа в сутках, больше в этом нет никакого смысла, кроме как декоративного.
Реально, таким же образом можно взять любую другую единицу назвать её как угодно, например 1 хрень будет равняться 123 секунды, большая хрень будет равняться 123 хрени. И мерить время по 123, но это же бред.
Очевидно, что часы и минуты это внесистемные единицы измерения. Внесистемная единица тогда имеет смысл, когда реально это добавляет удобства. Например, понятно для чего давление иногда измеряют в атмосферах, для наглядности сравнения с атмосферой Земли. Понятно почему расстояние измеряют в световых годах (расстояние которое свет проходит за год, если звезда находится на расстоянии 4 световых лет, то мы видим, то что происходило там 4 года назад). Даже понятно для чего нужны единицы как год и сутки, они привязаны к периоду обращения Земли вокруг солнца и вокруг себя.
Но какой практический смысл в себе несёт час или минута? НИКАКОГО. Вот вам и ответ.
Первое решение
Отказаться от часов и минут
Если мы хотим использовать большие числа измерения времени, можно использовать уже существующие приставки и не надо ничего выдумывать (кило-, мега- и т.д.).
Например, школьный урок идет 2.7 килосекунд, в сутках 86.4 килосекунд, продолжительность среднего фильма 5.7 килосекунд.
То есть уже все давно придумано, осталось только начать использовать то, что есть. Просто перестать заниматься детской игрой и не считать время по игрушечным неудобным единицам измерениям.
Примеры
Да это реально очень удобно, если вы попробуете, вы поймёте, что вам просто не нужно каждый раз делить на 60 или умножать. Ведь луюбая другая единица езмирения (не время) измеряется по нормальному. Более того, даже если мы во времени идем в меньшую сторону, то здесь тоже все окей (миллисекунды, микросекунды и т. д.). Но когда мы идём в большую сторону, начинается клоунада с минутами и часами. Это смешно. И теперь мы перейдём к следующему второму пункту.
Второе решение
Использовать только один часовой пояс и это UTC -2
Да. И это правильно. Часовые пояса имеют некий смысл, что ваше время синхронизируется с восходом и закатом солнца. Но в эпоху глобализации это приносит гораздо больше неудобств, чем пользы. Если вы живете в каком-то городе больше месяца, вы наверняка уже привыкли, что работа начинается в 9 вечера, а возвращаетесь домой вы в 5 утра, например. К этому можно легко привыкнуть. Но зато теперь вы не будете в следующий раз заходить на очередной сайт и не понимать во сколько времени начнётся ваш любимый футбольный матч или матч по доте 2. Реально, так достали эти часовые пояса, каждый раз приходиться подстраивать время под ваше местоположение. Но в реальности время протекает везде одинокого и никак не зависит от того, в какой точке пространства вы находитесь.
Почему UTC – 2 ?
Очень просто. Это почти единственный часовой пояс, в не находиться почти не один континент, кроме Гренландии. Чтобы никому не было обидно (хотя бы не так сильно). Был выбран этот пояс, но на самом деле это даже не важно. Можно выбрать любой другой пояс. Главное, чтобы он был единым и для всех
Теперь вы живёте счастливой жизнью
Если просто принять два правила: отменить часы, минуты и отменить часовые пояса. И станет настолько проще жить, что весь мир удивиться. Все эти конструкции придумал человек. И это можно объяснить как наследие, которое нам осталось от наших предков. Но это не значит что мы должны оставаться на месте. Каждое новое поколение совершенствует разработки прошлых лет и таким образом человечество двигаете в прогрессивное будущее.
Не можешь победить – присоединяйся!
Если вас заинтересовала эта (простая, но с очень глубоким смыслом) концепция. Предлагаю всем творческим людям, разработчикам и т. д. помочь в распространении этой идеи. Используйте в своих приложениях (или других товарах) время только в секундах и часового пояса UTC-2. Я размещу вас на своём сайте.
Что можно сделать
Если вы используете эту концепцию в вашем продукте, я также размещу его на своем сайте.
Вот набросок из того, что можно сделать:
создать настольные/настенные часы, которые показывают время в секундах
Создать приложение, которое показывает время в телефоне в секундах в UTC-2
Написать мне в личку
Береста
Береста – это кора берёзы. Подобно тому как наши предки записывали записки на бересте, вы также можете записывать все свои заметки в этом приложении. Оно полностью синхронизируете в реальном времени со всеми устройствами. Также ведет историю всех ваших записей и анализирует их. Также вы можете создавать флешбеки и менять этапы жизни. Тогда вы можете полностью отследить свою историю жизни. Также это первое приложение, которое поддерживает концепцию БЕЗ ЧАСОВ.
JavaScript. WebRTC. Соединение браузеров напрямую без сервера, peer-to-peer / Хабр | Веб-студия Nat.od.ua
JavaScript. WebRTC. Соединение браузеров напрямую без сервера, peer-to-peer / Хабр
Рис 1. Одновременная работа в редакторе блок схем с помощью WebRTC
WebRTC позволяет браузерам обмениваться информацией напрямую без сервера. Можно передавать видео, звук и данные.
Для соединения браузеры должны обменяться параметрами соединения: SDP и ICECandidate-ами
SDP описывает требования к соединению: что будет передаваться видео/аудио/ текст, какие кодеки поддерживаются. ICECandidate-ы это адреса, куда можно посылать пакеты.
Для WebRTC соединения нужно:
Обменяться требованиями к соединению.
Обменяться адресами.
Обмен параметрами соединения называется Signaling
Обменяться параметрами можно вручную через мессенджер или сделать сигнальный сервер.
Соединения между браузерами еще нет, но нужно обменяться начальными параметрами – см. Рис 2.
Параметры представлены в виде строк. Их можно отправлять друг другу вручную, например через мессенджер.
Можно автоматизировать. Сделать сигнальный сервер, который будет пересылать параметры между клиентами.
Обмен требованиями к соединению: SDPOffer, SDPAnswer
Требования к соединению зависят от задачи. Например, для видеосвязи браузеры должны выбрать кодек, который оба поддерживают. В браузерах есть API для формирования SDP.
См. Рис 2. “Session descriptors exchange”.
Алиса формирует SDPOffer с указанием поддерживаемых кодеков. Отправляет Бобу.
Боб получает SDPOffer и на его основе формирует SDPAnswer: выбирает кодек который есть у него и в SDPOffer. Обратите внимание – нельзя сформировать SDPAnswer без SDPOffer. Боб отправляет SDPAnswer Алисе.
Алиса устанавливает SDPAnswer: для трансляции будет использоваться кодек из SDPAnswer.
Обмен адресами: ICECandidate-ами
ICECandidate-ов может быть несколько. Например один адрес в локальной сети, другой во внешней. Чтобы узнать свой адрес нужен STUN сервер.
См. Рис 2. “Address exchange”.
Алиса узнает свои адреса по которым она может получать пакеты. И отправляет их Бобу. Боб выбирает из полученных адресов-кандидатов.
У Алисы может быть несколько адресов. Например один адрес в локальной сети, другой во внешней. Если Боб в той же локальной сети, Алиса и Боб соединяться по локальному адресу.
Браузер не знает свой адрес. Чтобы узнать свой адрес браузер делает запрос к специальному STUN серверу. STUN сервер сообщает браузеру его (браузера) внешний адрес. Есть публичные STUN сервера, например у Google.
Хорошая статья про узнавание своих адресов: Просто о WebRTC.
Можно сразу получить все свои ICECandidate-ы и отправить в составе SDP
В этом случае Боб сразу получает все необходимые параметры для соединения. Но, почему то, даже зная все ICECandidate-ы Алисы, не может ответить по WebRTC. Все равно нужно передать SDPAnswer через signaling.
Рис 3. Установка WebRTC соединения, ICECandidates посылаются в составе SDP
Обратите внимание: Боб не может отправить SDPAnswer по WebRTC. Пока Алиса не установит SDPAnswer – WebRTC не случится. Почему так – не понятно.
Из-за этого ограничения приходится делать сигнальный сервер. Если бы не ограничение, Алиса могла бы отправить Бобу ссылку с зашитыми параметрами. Боб мог бы получить из ссылки все что нужно и сразу установить WebRTC.