Frontend | Вопросы собесов
Сайт easyoffer.ru Реклама @easyoffer_adv ВП @easyoffer_vp Тесты t.me/+T0COHtFzCJkwMDUy Задачи t.me/+_tcX2w2EmvdmMTgy Вакансии t.me/+CgCAzIyGHHg0Nzky
Больше📈 Аналитический обзор Telegram-канала Frontend | Вопросы собесов
Канал Frontend | Вопросы собесов (@easy_javascript_ru) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 18 281 подписчиков, занимая 7 343 место в категории Технологии и приложения и 36 918 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 18 281 подписчиков.
Согласно последним данным от 13 июня, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -122, а за последние 24 часа — -9, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 9.43%. В первые 24 часа после публикации контент обычно набирает 5.83% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 1 725 просмотров. В течение первых суток публикация набирает 1 066 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 8.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как ставь, браузер, html, border, flex.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Сайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp
Тесты t.me/+T0COHtFzCJkwMDUy
Задачи t.me/+_tcX2w2EmvdmMTgy
Вакансии t.me/+CgCAzIyGHHg0Nzky”
Благодаря высокой частоте обновлений (последние данные получены 14 июня, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
useEffect позволяет выполнять побочные эффекты, такие как запросы к серверу, в функциональных компонентах.
import React, { useState, useEffect } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []); // Пустой массив означает, что эффект выполнится только при монтировании компонента
return (
<div>
{data ? (
<pre>{JSON.stringify(data, null, 2)}</pre>
) : (
<p>Loading data...</p>
)}
</div>
);
}
export default DataFetchingComponent;
🚩Методы жизненного цикла в классовых компонентах
Метод componentDidMount используется для выполнения запросов к серверу в классовых компонентах после монтирования компонента.
import React, { Component } from 'react';
class DataFetchingComponent extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
};
}
componentDidMount() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
this.setState({ data });
})
.catch(error => {
console.error('Error fetching data:', error);
});
}
render() {
const { data } = this.state;
return (
<div>
{data ? (
<pre>{JSON.stringify(data, null, 2)}</pre>
) : (
<p>Loading data...</p>
)}
</div>
);
}
}
export default DataFetchingComponent;
🟠Сервисы или утилиты
Запросы к серверу можно изолировать в отдельные файлы сервисов или утилит, что помогает сделать код более модульным и переиспользуемым.
service.js
export async function fetchData() {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
DataFetchingComponent.js
import React, { useState, useEffect } from 'react';
import { fetchData } from './service';
function DataFetchingComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData()
.then(data => setData(data))
.catch(error => console.error('Error fetching data:', error));
}, []);
return (
<div>
{data ? (
<pre>{JSON.stringify(data, null, 2)}</pre>
) : (
<p>Loading data...</p>
)}
</div>
);
}
export default DataFetchingComponent;
🟠Управление состоянием
Для крупных приложений, где важно централизованное управление состоянием, запросы к серверу можно выполнять в рамках таких библиотек, как Redux или MobX.
Ставь 👍 и забирай 📚 Базу знанийconsole.log("1: Перед запросом");
setTimeout(() => {
console.log("2: Данные загружены");
}, 2000);
console.log("3: После запроса");
Вывод в консоль
1: Перед запросом 3: После запроса 2: Данные загружены (спустя 2 секунды)🚩Обработка пользовательских событий без зависаний Если бы JavaScript не мог обрабатывать события асинхронно, то нажатия кнопок, прокрутка страницы и другие действия зависали бы, пока выполняется тяжёлая операция. Event Loop ставит события (например,
click, keydown) в очередь и обрабатывает их только когда основной поток свободен.
document.querySelector("button").addEventListener("click", () => {
console.log("Кнопка нажата!");
});
🚩Загрузка данных без блокировки страницы
Когда мы загружаем данные с сервера (fetch, setTimeout, setInterval), они не приходят мгновенно. Без Event Loop браузер бы зависал в ожидании ответа.
Асинхронные запросы (fetch, XMLHttpRequest) выполняются в фоновом режиме. Когда ответ готов, он помещается в очередь задач и обрабатывается, когда основной поток освободится.
console.log("Запрос данных...");
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => console.log("Данные получены:", data));
console.log("Код выполняется дальше!");
Вывод
Запрос данных...
Код выполняется дальше!
(Спустя время) Данные получены: {id: 1, title: "..."}
🚩Обход блокировки в тяжёлых вычислениях
Если в коде идёт сложная операция (например, сложные вычисления или рендеринг огромного списка), интерфейс зависнет.
Можно разбить задачу на части и выполнять её постепенно с помощью setTimeout или requestAnimationFrame.
let count = 0;
function heavyTask() {
for (let i = 0; i < 1e6; i++) {
count++;
}
console.log("Часть работы выполнена!");
if (count < 5e6) {
setTimeout(heavyTask, 0); // Даем Event Loop обработать другие задачи
}
}
heavyTask();
Ставь 👍 и забирай 📚 Базу знаний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();
Ставь 👍 и забирай 📚 Базу знаний<canvas>. WebGL позволяет использовать мощность графического процессора (GPU) для отрисовки сложных сцен, анимаций и интерактивных приложений прямо в браузере.
🚩Зачем нужен WebGL?
🟠Рендеринг 3D-графики в браузере
Без WebGL для создания сложных 3D-сцен в вебе приходилось использовать Flash, Java-апплеты или другие технологии. WebGL делает это нативно в браузере.
🟠Использование аппаратного ускорения
WebGL использует мощность видеокарты (GPU), а не только центрального процессора (CPU), что значительно ускоряет обработку графики.
🟠Работа в разных браузерах и на разных устройствах
WebGL работает на большинстве современных браузеров (Chrome, Firefox, Edge, Safari) и поддерживается на Windows, macOS, Linux, iOS и Android.
🟠Поддержка интерактивных приложений
Используется в играх, 3D-графике, симуляциях, картографических сервисах (например, Google Maps, Cesium.js), визуализациях данных.
🟠🚩ак использовать WebGL?
WebGL управляет графикой через шейдеры — небольшие программы, которые выполняются на видеокарте. Для работы с WebGL обычно используются библиотеки, упрощающие разработку, например:
- Three.js — высокоуровневая библиотека для удобной работы с WebGL.
- Babylon.js — мощный движок для создания 3D-приложений.
- PixiJS — библиотека для 2D-графики с поддержкой WebGL.
<canvas id="webgl-canvas"></canvas>
<script>
// Получаем WebGL-контекст
const canvas = document.getElementById("webgl-canvas");
const gl = canvas.getContext("webgl");
if (!gl) {
console.error("WebGL не поддерживается");
}
// Устанавливаем цвет фона и очищаем экран
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Черный фон
gl.clear(gl.COLOR_BUFFER_BIT);
</script>
Ставь 👍 и забирай 📚 Базу знанийasync
Используется перед объявлением функции. Это позволяет функции автоматически возвращать промис. Если эта функция возвращает не промис, то возвращаемое значение будет автоматически обернуто в промис.
async function fetchData() {
return 'данные';
}
fetchData().then(data => console.log(data)); // выводит "данные"
🚩Ключевое слово await
Используется для ожидания результата промиса внутри асинхронной функции async. Оно приостанавливает выполнение асинхронной функции до тех пор, пока промис не выполнится (т.е. не будет разрешен или отклонен). ЕЕ можно использовать только внутри асинхронных функций.
async function fetchData() {
let data = await fetch('https://api.example.com/data');
let json = await data.json();
return json;
}
🚩Плюсы
➕Улучшение читаемости кода
Асинхронный код, написанный с использованием async/await, выглядит более структурированным и похожим на синхронный код, что упрощает его понимание
➕Упрощение обработки ошибок
В асинхронных функциях с await можно использовать стандартный синтаксис try/catch для обработки ошибок, что делает код единообразнее.
➕Избегание "callback hell"
Использование async/await позволяет избежать сложностей с вложенными коллбэками, которые могут возникнуть при использовании промисов или старого стиля асинхронного кода с коллбэками.
Ставь 👍 и забирай 📚 Базу знанийviewport:
<meta name="viewport" content="width=device-width, initial-scale=1">
🟠Проблема без `meta viewport` (почему он нужен?)
Без viewport (по умолчанию)
На мобильных браузерах страницы загружаются как на ПК, но уменьшаются. Пользователям приходится зумить и скроллить.
🟠Дополнительные параметры `meta viewport`
Управление масштабом
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
Отключение адаптации iOS Safari
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
Ставь 👍 и забирай 📚 Базу знаний{} исторически использовались как ассоциативные массивы (ключ-значение), у Map есть ряд преимуществ, которые делают его более удобным в большинстве случаев.
🟠`Map` может использовать любые типы данных в качестве ключей
В объектах {} ключи всегда автоматически приводятся к строке.
const obj = {};
const key1 = {};
const key2 = {};
obj[key1] = "value1";
obj[key2] = "value2";
console.log(obj); // { '[object Object]': 'value2' }
console.log(obj[key1]); // "value2" (ключи перезаписались, потому что оба стали "[object Object]")
Пример с Map:
const map = new Map();
map.set(key1, "value1");
map.set(key2, "value2");
console.log(map.get(key1)); // "value1"
console.log(map.get(key2)); // "value2"
🟠`Map` хранит порядок ключей
В объекте {} порядок ключей не гарантируется (особенно для числовых ключей).
const obj = { 2: "two", 1: "one", 3: "three" };
console.log(Object.keys(obj)); // ["1", "2", "3"] (порядок числовых ключей изменился!)
Пример с Map
const map = new Map();
map.set(2, "two");
map.set(1, "one");
map.set(3, "three");
console.log([...map.keys()]); // [2, 1, 3] (порядок сохраняется!)
🟠`Map` быстрее при частых добавлениях/удалениях
Объекты {} оптимизированы для хранения структуры данных, но операции delete и Object.keys(obj).length могут быть медленными, потому что движок JavaScript выполняет дополнительные проверки.
Разница в скорости
В Map операции .set(), .get(), .delete() выполняются быстрее.
В объекте {} delete obj[key] может работать медленнее, так как JavaScript оптимизирует объекты для других целей.
🟠У `Map` есть удобные методы
Объект {} не имеет встроенных методов для работы с ключами и значениями. Чтобы, например, узнать размер объекта, приходится использовать Object.keys(obj).length.
const map = new Map();
map.set("a", 1);
map.set("b", 2);
console.log(map.size); // 2
console.log(map.has("a")); // true
console.log(map.delete("b")); // true (удалит "b")
В объекте {}
const obj = { a: 1, b: 2 };
console.log(Object.keys(obj).length); // 2 (нужно вызывать Object.keys())
console.log(obj.hasOwnProperty("a")); // true (менее удобный синтаксис)
delete obj.b; // Удаление ключа
🟠`Map` не имеет проблем с прототипами
В объекте {} могут быть неожиданные проблемы, если ключ совпадает с именем встроенного метода.
const obj = {};
console.log(obj.toString); // [Function: toString] (унаследованное свойство!)
console.log(obj["toString"]); // [Function: toString] (может вызвать баги)
Чтобы обойти это, приходится делать так
const obj = Object.create(null); // Теперь у объекта нет прототипа
obj.toString = "custom";
console.log(obj.toString); // "custom"
В Map таких проблем нет
const map = new Map();
map.set("toString", "custom");
console.log(map.get("toString")); // "custom" (никаких багов!)
Ставь 👍 и забирай 📚 Базу знаний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"
Ставь 👍 и забирай 📚 Базу знаний
Уже доступно! Исследование Telegram 2025 — ключевые инсайты года 
