Frontend | Вопросы собесов
Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv
Show more📈 Analytical overview of Telegram channel Frontend | Вопросы собесов
Channel Frontend | Вопросы собесов (@easy_javascript_ru) in the Russian language segment is an active participant. Currently, the community unites 17 873 subscribers, ranking 7 135 in the Technologies & Applications category and 36 813 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 17 873 subscribers.
According to the latest data from 27 August, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -162 over the last 30 days and by -8 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 6.80%. Within the first 24 hours after publication, content typically collects 4.51% reactions from the total number of subscribers.
- Post reach: On average, each post receives 1 216 views. Within the first day, a publication typically gains 806 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 4.
- Thematic interests: Content is focused on key topics such as ставь, браузер, html, border, flex.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy
Контакт для рекламы: @easyoffer_adv”
Thanks to the high frequency of updates (latest data received on 28 August, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
@media print, которое позволяет задать специальные стили для печати.
🟠Использование `@media print`
Вы можете задать стили, которые будут применяться только при печати
@media print {
body {
font-size: 12pt; /* Оптимальный размер шрифта */
color: black; /* Убираем цветной текст для экономии чернил */
background: none !important; /* Убираем фон */
}
}
🟠Убираем ненужные элементы (меню, рекламу, анимации)
Некоторые элементы (например, навигация, футер, кнопки) не нужны при печати, их можно скрыть
@media print {
nav, .sidebar, .ads, .button {
display: none; /* Скрываем ненужное */
}
}
🟠Изменяем ширину страницы и текст
Обычно страницы шире, чем лист бумаги. Можно задать max-width для удобства
@media print {
body {
width: 100%;
max-width: 800px; /* Уменьшаем ширину */
margin: auto; /* Центрируем */
}
}
Заменяем цвета на чёрно-белые (экономия чернил)
@media print {
a {
color: black !important; /* Делаем ссылки чёрными */
text-decoration: underline; /* Добавляем подчёркивание */
}
}
🟠Добавляем URL ссылок в текст
При печати гиперссылки не работают, поэтому можно показать их адрес
@media print {
a::after {
content: " (" attr(href) ")"; /* Добавляем URL рядом со ссылкой */
font-size: 10pt;
color: gray;
}
}
Избегаем разрывов страниц в неудобных местах
@media print {
h1, h2, h3 {
page-break-after: avoid; /* Не разрываем страницу после заголовка */
}
p {
page-break-inside: avoid; /* Не разрываем абзац на две страницы */
}
}
Ставь 👍 и забирай 📚 Базу знанийxxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx.
Генерация с помощью crypto.randomUUID() (современный способ)
const id = crypto.randomUUID();
console.log(id); // Например: "3d593c8e-7a34-45f7-9a14-2f5f5788d4ec"
Использование библиотеки uuid
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
console.log(id); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
🟠Хеш-функции (SHA, MD5)
Если нужно вычислить уникальный идентификатор на основе входных данных (например, строки или объекта), можно использовать хеш-функции.
SHA-256 через crypto.subtle
async function generateHash(input) {
const encoder = new TextEncoder();
const data = encoder.encode(input);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
return [...new Uint8Array(hashBuffer)].map(b => b.toString(16).padStart(2, '0')).join('');
}
generateHash("hello").then(console.log);
// Например: "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
🟠Генерация случайного идентификатора
Если нужна просто случайная строка, можно использовать Math.random().
Базовая генерация ID
const id = Math.random().toString(36).substring(2, 10);
console.log(id); // Например: "5g7f8a1z"
Более безопасный вариант с crypto.getRandomValues()
function generateRandomId(length = 16) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return [...array].map(b => b.toString(16).padStart(2, '0')).join('');
}
console.log(generateRandomId(8)); // Например: "a3f9b8c7"
🟠Инкрементальные ID
Если нужно просто увеличивающееся число (например, ID для записей в массиве), можно использовать счётчик
let counter = 0;
function generateIncrementalId() {
return ++counter;
}
console.log(generateIncrementalId()); // 1
console.log(generateIncrementalId()); // 2
console.log(generateIncrementalId()); // 3
🟠Хеширование строки (например, объекта)
Можно создать ID, основываясь на JSON-объекте.
function hashObject(obj) {
return JSON.stringify(obj)
.split("")
.reduce((hash, char) => {
return ((hash << 5) - hash) + char.charCodeAt(0);
}, 0)
.toString(16);
}
console.log(hashObject({ name: "Alice", age: 25 })); // Например: "-3d4e5f"
Ставь 👍 и забирай 📚 Базу знанийdocument.querySelectorAll("button").forEach((btn) => {
btn.addEventListener("click", () => {
console.log("Кнопка нажата");
});
});
Если кнопок 1000, это создаст 1000 обработчиков, что неэффективно.
Если кнопки добавляются динамически (например, из API), обработчик на новые кнопки не сработает.
🟠Делегирование событий (оптимальный способ)
Вместо того чтобы вешать обработчик на каждую кнопку, ставим один обработчик на родительский элемент и проверяем, кто вызвал событие:
document.getElementById("container").addEventListener("click", (event) => {
if (event.target.tagName === "BUTTON") {
console.log("Кнопка нажата:", event.target.textContent);
}
});
🟠Пример с динамическими элементами
Если мы добавляем кнопки динамически, обработчик все равно будет работать
document.getElementById("container").addEventListener("click", (event) => {
if (event.target.classList.contains("btn")) {
console.log("Нажата кнопка:", event.target.textContent);
}
});
// Добавляем новую кнопку динамически
setTimeout(() => {
const newButton = document.createElement("button");
newButton.classList.add("btn");
newButton.textContent = "Новая кнопка";
document.getElementById("container").appendChild(newButton);
}, 2000);
Ставь 👍 и забирай 📚 Базу знаний<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
🟠Через тег `<img>`
Если SVG не нужно изменять, можно вставить его как обычное изображение.
<img src="image.svg" alt="Описание изображения" width="100" height="100">
🟠Через CSS `background-image`
SVG можно использовать как фоновое изображение.
<div class="icon"></div>
<style>
.icon {
width: 100px;
height: 100px;
background-image: url('image.svg');
background-size: cover;
}
</style>
🟠Через тег `<object>`
Позволяет загружать SVG-файлы и взаимодействовать с ними.
<object type="image/svg+xml" data="image.svg" width="100" height="100"></object>
🟠Через тег `<iframe>`
SVG можно загружать в iframe.
<iframe src="image.svg" width="100" height="100"></iframe>
Ставь 👍 и забирай 📚 Базу знанийvar globalVar = 'Я глобальная переменная';
function testFunction() {
console.log(globalVar); // Доступно
}
testFunction();
console.log(globalVar); // Доступно
🚩Функциональная область видимости
Переменные, объявленные с помощью var внутри функции, имеют область видимости, ограниченную этой функцией. Они недоступны за её пределами.
function testFunction() {
var functionVar = 'Я внутри функции';
console.log(functionVar); // Доступно
}
testFunction();
console.log(functionVar); // Ошибка: переменная functionVar недоступна
🚩Блочная область видимости
Переменные, объявленные с помощью let и const, имеют область видимости, ограниченную ближайшим блоком {}.
if (true) {
let blockVar = 'Я внутри блока';
console.log(blockVar); // Доступно
}
console.log(blockVar); // Ошибка: переменная blockVar недоступна
🚩Область видимости модуля (Module Scope)
При использовании модулей (например, import и export в ES6), все переменные и функции в модуле имеют собственную область видимости. Они не попадают в глобальную область видимости.
export const myVar = 'Я переменная из модуля';
import { myVar } from './module1.js';
console.log(myVar); // "Я переменная из модуля"
Ставь 👍 и забирай 📚 Базу знанийasync/await делает код чище, проще и удобнее.
🟠`async/await` проще читать и писать
Код на Promise.then() часто становится вложенным и запутанным
fetch("https://api.example.com/user")
.then(response => response.json())
.then(user => {
return fetch(`https://api.example.com/orders/${user.id}`);
})
.then(response => response.json())
.then(orders => {
console.log("Заказы:", orders);
})
.catch(error => console.error("Ошибка:", error));
Решение: async/await
async function getUserOrders() {
try {
const response = await fetch("https://api.example.com/user");
const user = await response.json();
const ordersResponse = await fetch(`https://api.example.com/orders/${user.id}`);
const orders = await ordersResponse.json();
console.log("Заказы:", orders);
} catch (error) {
console.error("Ошибка:", error);
}
}
getUserOrders();
async/await лучше обрабатывает ошибки
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => {
throw new Error("Ошибка в обработке данных");
})
.catch(error => console.error("Ошибка:", error));
async/await + try/catch – мощная обработка ошибок
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) throw new Error("Ошибка HTTP " + response.status);
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Ошибка:", error);
}
}
fetchData();
async/await удобен в for и try/catch
const urls = ["url1", "url2", "url3"];
urls.forEach(url => {
fetch(url)
.then(response => response.json())
.then(data => console.log(data));
});
async/await в for of
async function fetchAll(urls) {
for (const url of urls) {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}
}
fetchAll(["url1", "url2", "url3"]);
async/await работает с try/finally
async function fetchData() {
try {
console.log("Запрос данных...");
const response = await fetch("https://api.example.com");
const data = await response.json();
console.log("Данные:", data);
} catch (error) {
console.error("Ошибка:", error);
} finally {
console.log("Закрываем соединение...");
}
}
fetchData();
async/await можно использовать внутри Promise.all()
Иногда Promise.all() быстрее, потому что запускает промисы параллельно.
async function fetchMultiple() {
const [user, orders] = await Promise.all([
fetch("https://api.example.com/user").then(res => res.json()),
fetch("https://api.example.com/orders").then(res => res.json())
]);
console.log(user, orders);
}
fetchMultiple();
Ставь 👍 и забирай 📚 Базу знанийstate) или свойства (props) изменяются. Однако часто это приводит к ненужным рендерам, которые можно избежать.
🚩Почему важна оптимизация рендеринга?
🟠Производительность
Чем больше компонентов рендерится без необходимости, тем больше времени тратится на вычисления и обновления DOM.
🟠Экономия ресурсов
Избегая лишних рендеров, приложение работает быстрее, а пользовательский интерфейс становится более отзывчивым.
🟠Лучший UX
Плавная работа интерфейса критична для сложных приложений с большим количеством данных.
🚩Основные подходы к оптимизации рендеринга
🟠Мемоизация компонентов
React предоставляет утилиту React.memo, чтобы предотвращать ререндеринг компонента, если его props не изменились.
import React from 'react';
const MyComponent = React.memo(({ count }) => {
console.log('Рендер компонента');
return <div>Счётчик: {count}</div>;
});
// Использование
export default function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<MyComponent count={count} />
<button onClick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}
🟠Использование `useMemo` и `useCallback`
Эти хуки используются для предотвращения повторных вычислений и создания функций при каждом рендере.
import React, { useMemo } from 'react';
function ExpensiveCalculationComponent({ number }) {
const calculatedValue = useMemo(() => {
console.log('Выполняются сложные вычисления...');
return number ** 2;
}, [number]); // Пересчитывается только если `number` изменился
return <div>Результат: {calculatedValue}</div>;
}
Пример useCallback
import React, { useCallback, useState } from 'react';
const Child = React.memo(({ onClick }) => {
console.log('Рендер дочернего компонента');
return <button onClick={onClick}>Кликни меня</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Кнопка нажата');
}, []); // Создаётся одна и та же функция между рендерами
return (
<div>
<Child onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Увеличить {count}</button>
</div>
);
}
🟠Разделение кода и ленивый рендеринг
Использование React.lazy и Suspense позволяет загружать компоненты только тогда, когда они необходимы.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<LazyComponent />
</Suspense>
);
}
🟠Проверка зависимости в `useEffect`
Избегайте запуска побочных эффектов, если зависимости не изменились.
React.useEffect(() => {
console.log('Эффект сработал!');
}, [/* следите только за нужными зависимостями */]);
🟠Избегайте анонимных функций и объектов в `props`
Передача новых объектов и функций через props вызывает лишние рендеры.
<ChildComponent data={{ key: 'value' }} />
Лучше так
const data = { key: 'value' };
<ChildComponent data={data} />;
🟠Разделение больших компонентов
Если компонент слишком сложный, разделите его на более мелкие, чтобы React мог эффективно управлять состоянием и перерисовкой.
🟠Использование ключей при рендере списков
Каждый элемент списка должен иметь уникальный ключ, чтобы React мог правильно отслеживать изменения.
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
Ставь 👍 и забирай 📚 Базу знаний