Исключения в JavaScript: обработка ошибок с помощью try, catch, throw, finally
Ловим и обрабатываем ошибки с использованием JavaScript-инструментов.
 
 
При работе веб-сайта в реальном времени могут возникать ошибки — например, при проверке, заполнил ли пользователь все поля для регистрации, или при обращении веб-сервиса к серверу. Эти ошибки называются исключениями в JavaScript. Можно поймать исключения и предотвратить крах программы.
Сегодня вы узнаете, что такое исключения в JavaScript, какие виды ошибок и исключений бывают и как они обрабатываются с помощью механизма try…catch, а также напишете своё первое исключение на JavaScript.
Содержание
- Что такое исключения и ошибки в JavaScript
- Какие бывают ошибки
- Конструкция try-catch в исключениях JavaScript
- Блок finally в исключениях JavaScript
- Объект Error и его свойства в JavaScript
- Выброс исключения throw в JavaScript
- Как правильно обрабатывать асинхронные ошибки в JavaScript
- Практика: проектируем систему ошибок в приложении JavaScript
- Частые ошибки при работе с исключениями в JavaScript
- Когда использовать исключения
- Когда можно обойтись без исключений
- Что ещё почитать
Что такое исключения и ошибки в JavaScript
Исключения (exceptions) в JavaScript — это ошибки в процессе компиляции или выполнении кода. Например, пользователь не заполнил на сайте обязательное поле «Имя» и нажал кнопку «Зарегистрироваться» — случилось исключение.
Создатели JS предусмотрели такие случаи. Чтобы программа не вылетала после ошибки, в коде используют специальные языковые конструкции — try, catch, finally. Ещё это называют обработкой исключений. Если не обработать исключение, скрипт может сломаться и дальнейшая работа сервиса станет непредсказуемой.
try {
  // Код, где может произойти ошибка
} catch (error) {
  // Выполнится, если ошибка произошла
} finally {
  // Дополнительный блок
  // Выполнится после всех событий
}Какие бывают ошибки
В JavaScript бывают разные ошибки, и за каждый вид отвечает определённый класс:
- SyntaxError — синтаксическая ошибка (например, забыта скобка).
// Пропущены закрывающие скобки 
eval("function test() { console.log('Hello'");- ReferenceError — ошибка ссылки (обращение к несуществующей переменной — адрес ссылки, которого нет).
// Обращение к несуществующей переменной — адрес ссылки, которого нет)
console.log(nonExistentVariable);- TypeError — ошибка типа (неверный тип данных).
// Попытка вызвать число как функцию
let num = 16;
num();- RangeError — ошибка диапазона (обращение к несуществующему индексу массива).
// Отрицательная длина массива
let arr = new Array(-5);- URIError — возникает при работе функций encodeURI, decodeURI, если они получают неверный аргумент.
// Символ % без кода — неправильный URI
decodeURIComponent('%');- EvalError — возникает при некорректной работе eval(), функции, которая берёт строку кода и выполняет её.
// Искусственно создаём EvalError
throw new EvalError("Некорректное использование eval()");- AggregateError — возникает, когда несколько ошибок происходит одновременно.
// Ждёт первый успешный промис
Promise.any([
  Promise.reject("Ошибка A"),
  Promise.reject("Ошибка B")
])
.catch(e => console.log(e));Конструкция try-catch в исключениях JavaScript
В блоке try пишется код, в котором может возникнуть исключение, а в catch пишется код, который выполнится, если какая-то ошибка всё же произошла. Оба элемента пишутся в фигурных скобках. Они зависят друг от друга и не могут существовать по отдельности.
try {
    // Код, который может вызвать ошибку
} catch (error) {
    // Код, который выполняется при появлении ошибки в блоке try
    console.error("Ошибка: ", error.message);
}Если запустить этот код без try…catch, вылетит исключение.
start(); // Такой функции нет
console.log("Привет"); // Не выполнитсяВесь код JavaScript содержит только эти две строки. Никакого метода start() в JavaScript не существует, и в консоли после выполнения этой строки вы увидите Uncaught ReferenceError: start is not defined, а строчка с сообщением «Привет» и весь дальнейший код не будут выполнены.

Обновим код, используя try и catch. В try положим код, который может выдать ошибку, а в catch — сообщение об ошибке:
try {
    start(); // Uncaught ReferenceError: start is not defined
    console.log("Привет"); // Этот код не выполнится
} catch (error) {
    console.error("Ошибка поймана. Исключение:", error.message);
}
console.log("Ещё раз привет"); // Этот код выполнитсяИсключение обработано. Теперь код выполнится дальше, но следующие строки кода в try не выполнятся, как и console.log("Привет");. Далее мы увидим действия из catch, а потом код продолжит выполняться.
Вывод в консоль будет таким:
❌index.html:23 Ошибка поймана. Исключение: start is not defined
Ещё раз приветВ JavaScript блок catch может быть только один, в отличие от Java, C++ или Python. Это связано с особенностью языка — он упрощён и адаптирован для разработки веб-сервисов.
Если нужно обработать несколько разных исключений за раз, используйте конструкцию switch или if…else для проверки типа внутри catch:
try {
    // Код, который может вызвать исключение
} catch (error) {
    switch (error.constructor) {
        case TypeError:
            // TypeError-исключение
            console.error("Ошибка типа:", error.message);
            break;
        case ReferenceError:
            // ReferenceError-исключение
            console.error("Ошибка ссылки:", error.message);
            break;
        case SyntaxError:
            // SyntaxError-исключение
            console.error("Синтаксическая ошибка:", error.message);
            break;
        default:
            console.error("Неизвестная ошибка:", error.message);
    }
}Блок finally в исключениях JavaScript
Блок finally — дополнительный блок в конструкции try…catch. Он выполняется в любом случае, было исключение или его не было, и пишется после блока catch. Такой блок необходим для завершения жизненно важных операций в случаях, когда произошла ошибка, всё сломалось и программа дальше работать не будет, но нужно сохранить данные или восстановить состояние.
В следующем JavaScript-коде всё хорошо, ошибок нет: catch не срабатывает, но событие в finally выполняется:
try {
    // Тут всё хорошо
    console.log("Начинаем выполнение");
    let result = 2 + 2;
    console.log("Результат:", result);
} catch (error) {
    // Никаких ошибок не было — код в catch не выполнится
    console.error("Ошибка:", error.message);
} finally {
    // Выполнится в любом случае
    console.log("Этот блок finally выполняется в любом случае");
}Консоль JavaScript:
Начинаем выполнение
Результат: 4
Этот блок finally выполняется в любом случаеЕсть ещё одна особенность: можно обойтись без catch и использовать только try и finally.
try {
    JSON.parse("невалидный JSON"); // Ошибка!
} finally {
    console.log("Финальный блок"); // Выполнится всегда
}
console.log("После try-finally"); // Не выполнитсяВ такой ситуации не будет проверок на ошибки, и блок finally гарантированно выполнится, работа программы хоть и некорректно, но завершится.
Консоль JavaScript:
Финальный блок
Объект Error и его свойства в JavaScript
Функция console.error("string", error) нужна, чтобы выводить в консоль форматированные ошибки. Она принимает два параметра, один из которых сама ошибка — объект класса Error.

Всё образовано от базового класса Object, унаследовано классом Error и распространяется на подклассы в зависимости от вида ошибки. За что отвечает каждый подкласс — описано выше.
У класса Error есть несколько основных свойств:
- name — имя класса ошибки;
- message — сообщение ошибки;
- stack — показать стек вызовов функций.
const err = new Error("Неверный тип"); // В конструкторе пишется message
console.log(err.name); // Имя класса ошибки
console.log(err.message); // Сообщение ошибки
console.log(err.stack); // Трассировка стека- cause — ссылка на другую ошибку (другой Error), причина другой ошибки.
const original = new Error("Исходная ошибка");
const errWithCause = new Error("Новая ошибка", { cause: original });
console.log(errWithCause.cause); //Error: Исходная ошибка
console.log(errWithCause.message); // Error: Новая ошибкаВыброс исключения throw в JavaScript
По капотом исключения работают так:
- Где-то на стороне пользователя происходит ошибка.
- Вылетает исключение в блоке try JavaScript, текущий код прерывается.
- Программа ищет нужный класс ошибок Error.
- Передаёт найденную ошибку в catch.
- Выполняется finally (если есть).
- Программа продолжает работу после блока try…catch.
Если мы натыкаемся на какой-либо Error, где-то в JavaScript выполняется строчка:
// С помощью throw создаётся и выбрасывается ошибка
throw new TypeError("Сообщение об ошибке");Можно создавать собственные ошибки. Исключение в JavaScript создаётся с помощью ключевого слова throw:
// Создаём свою ошибку и ловим её с помощью try ...catch
try{
    throw new Error("Новая ошибка");
}catch (error) {
    console.log(error.message); // Error: Новая ошибка
}Всё, что мы рассмотрели до этого, — синхронный код, то есть код, выполняющийся строчка за строчкой. Теперь рассмотрим особенности обработки исключений в случаях с асинхронным кодом.
Как правильно обрабатывать асинхронные ошибки в JavaScript
Асинхронный код в JavaScript — это код, который выполняется не сразу, а позже, после завершения других операций. Хотя JavaScript работает в одном потоке и выполняет команды по порядку, он умеет откладывать задачи, не мешая основному процессу. Это возможно благодаря очереди задач и механизму Event Loop.
Например, функция setTimeout() запускает другую функцию через заданное время. Но если внутри этой отложенной функции произойдёт ошибка, обычный try…catch её не поймает. Вот пример:
// Через 3 секунды произойдёт ошибка
// try...catch здесь работать не будет!
try{
  setTimeout(() => {
    throw new Error("Асинхронная ошибка");
  }, 3000);
}catch(error) { console.error(error.message); }
console.log("Скоро будет конец..."); // Эта надпись появится за 3 секунды до исключенияВ этом коде try…catch не сработает, потому что ошибка произойдёт позже, уже вне текущего блока. Сообщение «Скоро будет конец…» появится сразу, а ошибка — через 3 секунды, и она не будет обработана.
Чтобы правильно обрабатывать такие ошибки, нужно использовать другие подходы. Один из них — промисы (Promise). Это объект, который описывает результат асинхронной операции: если всё прошло успешно — вызывается resolve, если произошла ошибка — reject. Для обработки ошибок у промиса есть метод catch().
Вот как можно переписать пример с использованием промиса:
new Promise((_, reject) => {
  setTimeout(() => {
    reject(new Error("Асинхронная ошибка"));
  }, 3000);
})
.catch(error => {
  console.error("Ошибка поймана:", error.message);
});
console.log("Скоро будет конец...");Теперь ошибка будет поймана и выведена в консоль. Такой подход работает и с сетевыми запросами, и с другими задачами, которые не выполняются мгновенно.
Для удобства можно использовать async/await — это синтаксис, который делает асинхронный код более читаемым, как будто он работает синхронно. Но даже в этом случае ошибки нужно оборачивать в try…catch внутри async-функции.
Модернизируем предыдущий пример и представим, что мы отправляем запрос на сервер, чтобы получить список товаров. Сервер может вернуть ошибку, поэтому сразу предусмотрим такой вариант:
// Объявляем асинхронную функцию для получения товаров
async function getProducts() {
  try {
    // Создаём промис, который «симулирует» работу сервера
    // setTimeout через 3 секунды вызовет reject — то есть имитацию ошибки
    await new Promise((resolve, reject) => {
      setTimeout(() => {
        // Здесь специально выбрасываем ошибку
        reject(new Error("Сервер не отвечает"));
      }, 3000);
    });
    // Если бы промис завершился успешно (resolve), код пошёл бы дальше
    // Например:
    // console.log("Данные получены!");
  } catch (error) {
    // Блок catch перехватывает ошибку и выводит сообщение о ней
    console.log("Ошибка при получении данных:", error.message);
  }
}
// Вызываем функцию
getProducts();
// Эта строка выполнится сразу, так как асинхронная функция не блокирует поток
console.log("Запрос отправлен, ждём ответа от сервера...");- getProducts() — в нашем случае асинхронная функция, но async делает её похожей на синхронную.
- await — говорит, что нужно подождать, пока ответит сервер.
- reject(new Error()) — выбрасывает исключение, если «сервер не отвечает».
- try…catch — в данном примере поймает исключение, так как мы используем ключевые слова async/await. await можно и нужно оборачивать в try…catch, чтобы выловить исключение.
Практика: проектируем систему ошибок в приложении JavaScript
В большинстве приложений ошибки неизбежны. Проектирование системы ошибок помогает понять, что именно пошло не так, и ускоряет отладку. В этом уроке мы создадим собственную систему ошибок на JavaScript.
Шаг 1. Создаём HTML-файл для практики
Создайте файл index.html с базовой структурой:
<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <title>Исключения JavaScript</title>
    <script>
      // Здесь будет ваш JavaScript-код
    </script>
  </head>
  <body>
    <h1>Практика: Проектирование системы ошибок в приложении JavaScript</h1>
  </body>
</html>В реальных проектах JavaScript обычно выносится в отдельный JS-файл, но для учебных целей мы пишем код прямо внутри тега <script>.
Шаг 2. Создаём базовый класс ошибок приложения
Добавим в блок <script> собственный класс AppError, который будет основой для всех ошибок в нашем приложении:
class AppError extends Error {
  constructor(message, { code = "APP_ERROR", meta = {} } = {}) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
    this.meta = meta;
  }
}Этот класс позволяет задавать имя ошибки, код и дополнительные метаданные — удобно для логирования и отладки.
Шаг 3. Создаём специализированную ошибку — NetworkError
Теперь создадим класс NetworkError, который будет использоваться при отсутствии интернет-соединения:
class NetworkError extends AppError {
  constructor(message = "Нет интернета", meta = {}) {
    super(message, { code: "NETWORK_ERROR", meta });
  }
}Такая ошибка пригодится, если ваше приложение зависит от сетевых запросов.
Шаг 4. Пишем асинхронную функцию загрузки данных
Добавим функцию loadData(), которая имитирует сетевой запрос. Она использует ключевое слово async, а при отсутствии интернета выбрасывает исключение NetworkError.
async function loadData() {
  const online = false; // Имитируем отсутствие интернета
  if (!online) throw new NetworkError(); // Выбрасываем ошибку, если соединения нет
  return ["object01", "object02"]; // Возвращаем данные, если соединение есть
}Здесь видно, как проверка сетевого состояния встраивается в логику приложения.
Шаг 5. Вызываем функцию и обрабатываем исключения
Теперь вызовем loadData() внутри анонимной асинхронной функции. Мы используем конструкцию try…catch, чтобы перехватить возможные ошибки.
(async () => {
  try {
    const data = await loadData(); // Ожидаем результата
    console.log(data); // Выводим данные в консоль
  } catch (error) {
    if (error instanceof NetworkError) {
      console.warn("Проверьте подключение к интернету."); // Сообщение для пользователя
    } else {
      console.error("Ошибка:", error); // Лог других ошибок
    }
  }
})();Шаг 6. Проверяем результат в консоли браузера
Откройте файл index.html в браузере и включите DevTools (обычно клавиша F12). Перейдите на вкладку Console.
Вы увидите предупреждение:
Проверьте подключение к интернету.
Это значит, что исключение NetworkError было успешно выброшено, перехвачено и обработано. Код работает корректно, и система ошибок функционирует как задумано.
Частые ошибки при работе с исключениями в JavaScript
Использовали await, но не защитили асинхронный код
// Объявляем асинхронную функцию fetchData
async function fetchData() { 
    // Делаем HTTP-запрос к API по указанному адресу и ждём ответа
    const response = await fetch('https://example.com/api/data'); 
    
    // Преобразуем ответ из формата JSON в объект JavaScript
    const data = await response.json(); 
    
    // Выводим полученные данные в консоль
    console.log(data); 
} 
// Вызываем функцию, чтобы запустить загрузку данных
fetchData();Если ссылка будет некорректной или сервер вернёт ошибку, то программа зависнет или прекратит свою работу. Всегда обёртывайте асинхронный код. В текущем примере с async и await нам будет достаточно использовать try…catch:
// Объявляем асинхронную функцию для получения данных
async function fetchData() {
  try {
    // Делаем HTTP-запрос по адресу 'https://example.com/api/data'
    // fetch возвращает промис, поэтому используем await
    const response = await fetch('https://example.com/api/data');
    // Ответ от сервера нужно преобразовать в обычный объект/массив
    // .json() тоже возвращает промис, поэтому снова ставим await
    const data = await response.json();
    // Выводим полученные данные в консоль
    console.log(data);
  } catch (error) {
    // Если произошла ошибка (например, нет интернета или сервер не отвечает),
    // то она попадёт сюда
    console.error("Ошибка:", error.message);
  }
}
// Запускаем функцию
fetchData();Проигнорировали ошибки в промисах
// Функция fetchJSON принимает URL и возвращает промис
// 1) Вызываем fetch(url) — отправляем запрос на сервер
// 2) Когда ответ придёт, вызываем response.json()
//    Это тоже возвращает промис, который преобразует данные в объект/массив
const fetchJSON = url => fetch(url).then(response => response.json());
// Вызываем функцию и передаём URL
fetchJSON('https://example.com/bad-data') 
    // Когда данные успешно получены и преобразованы в JSON,
    // они попадают в .then(data => ...)
    .then(data => console.log(data));Функция fetch() — отвечает за отправку HTTP-запросов в JavaScript. Мы использовали функцию then() — она возвращает промис, но мы не указали функцию промиса catch() — в которой как раз будет обработана ошибка, если что-то пойдёт не так. Правильно написать код будет так:
// Вызываем функцию и передаём некорректный адрес
fetchJSON('https://example.com/bad-data') 
    // Если запрос успешный и данные корректные — попадём сюда
    .then(data => console.log(data)) 
    // Если произошла ошибка (например, сервер вернул плохие данные
    // или JSON нельзя разобрать) — сработает .catch()
    .catch(error => console.error("Ошибка:", error.message));Повторили обработчик ошибок
Следующий код сильно нагружает систему постоянной проверкой try…catch каждого элемента массива и делает JavaScript-код непонятным:
// Создаём массив чисел от 1 до 10
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Перебираем массив методом forEach
numbers.forEach(num => { 
    try {
        // Проверяем: если число нечётное — выбрасываем ошибку
        if (num % 2 !== 0) throw new Error(`${num} нечётное`);
        // Если число чётное — выводим его квадрат
        console.log(num * num); 
    } catch (error) {
        // Если поймали ошибку (нечётное число) — выводим сообщение
        console.error("Ошибка:", error.message); 
    }
});Исправим ситуацию, вытащив из цикла try…catch и обернув весь блок вне прохода по массиву. Технически теперь вместо десяти конструкций проверки исключений у нас остаётся только одна, производительность становится выше, а функциональность не меняется:
// Создаём массив чисел от 1 до 10
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Перебираем массив методом forEach
numbers.forEach(num => { 
    try {
        // Проверяем: если число нечётное — выбрасываем ошибку
        if (num % 2 !== 0) throw new Error(`${num} нечётное`);
        // Если число чётное — выводим его квадрат
        console.log(num * num); 
    } catch (error) {
        // Если поймали ошибку (нечётное число) — выводим сообщение
        console.error("Ошибка:", error.message); 
    }
});Когда использовать исключения
Исключения требуют ресурсов для обработки и могут сильно тормозить программу. Обрабатывать весь код в try…catch не нужно, используйте его только в местах, где действительно может произойти критическая ошибка, но прерывать работу сервиса нельзя.
Есть несколько случаев, в которых оправданно использовать исключения.
Работа с сетью, файловой системой, базой данных
Обращения к внешним источникам данных всегда сопряжены с риском. Сервер может не ответить, соединение может оборваться или придёт некорректный ответ.
Если не предусмотреть такие ситуации, приложение просто остановится с ошибкой. Чтобы этого не случилось, такие запросы нужно оборачивать в try…catch. Это позволяет перехватить сбой, показать сообщение пользователю и продолжить работу без краха всей системы.
try {
  // Отправляем HTTP-запрос на сервер
  // await заставляет JS ждать ответа от сервера
  const response = await fetch('https://api.example.com/data');
  // Преобразуем ответ в формат JSON
  // response.json() тоже возвращает промис, поэтому await нужен
  const data = await response.json();
  // Если всё прошло успешно, выводим данные в консоль
  console.log(data);
} catch (error) {
  // Если что-то пошло не так (сеть недоступна, сервер вернул ошибку,
  // JSON не удалось разобрать), управление попадает сюда
  console.error('Не удалось получить данные:', error.message);
  // Можно вызвать функцию для показа ошибки пользователю
  // Например, показать сообщение на странице
  showErrorMessage('Сервис временно недоступен');
}Парсинг входящих данных
Когда приложение получает данные извне — например, от сервера или из файла, — оно не может быть уверено, что формат будет правильным. Иногда приходит строка, которую нельзя разобрать как JSON: забыты кавычки, нарушена структура или просто передано не то, что ожидалось.
Если попробовать разобрать такую строку без проверки, программа может остановиться с ошибкой. Чтобы этого не произошло, нужно использовать try…catch — так можно перехватить исключение и продолжить работу, даже если данные оказались испорченными.
// Некорректный JSON
const userInput = '{ "Username": "Username123" }';
try {
  // Пробуем разобрать JSON-строку в объект JavaScript
  const obj = JSON.parse(userInput);
  // Пытаемся обратиться к свойству name объекта
  // Если в JSON такого поля нет, получим undefined
  console.log(obj.name);
} catch (error) {
  // Если JSON некорректный, выполнение перейдёт сюда
  // Например, если забыты кавычки или синтаксис неверный
  console.error('Ошибка парсинга JSON:', error.message);
}Когда можно обойтись без исключений
Отсутствие ожидаемых данных
Если нужный элемент не найден в массиве, это не сбой, а обычная ситуация. Например, у нас есть пользователь с несуществующим ID. Вместо исключения можно спокойно проверить это через if и вывести понятное сообщение. Ошибкой это не считается, и выбрасывать её не нужно.
// Массив объектов пользователей
const users = [
  { id: 1, name: 'Ann' },
  { id: 2, name: 'Kate' }
];
// Пытаемся найти пользователя с id = 3
// Метод .find() возвращает первый элемент, который подходит под условие
// Если такого элемента нет, вернёт undefined
const user = users.find(u => u.id === 3);
// Проверяем, найден ли пользователь
if (!user) {
  // Если user === undefined (не найден) — выводим сообщение
  console.log('Пользователь не найден');
} else {
  // Если пользователь найден — выводим его имя
  console.log('Имя пользователя:', user.name);
}Валидация данных от пользователя
Проверка данных, которые вводит пользователь, — это обычная часть работы приложения. Если, например, человек ввёл email без символа @, это не сбой программы, а просто некорректный ввод.
В таких случаях не нужно выбрасывать исключения. Гораздо проще и правильнее проверить данные через if, показать сообщение и попросить ввести заново. Это быстрее, понятнее и не перегружает систему.
// Функция проверяет, содержит ли строка символ @
// Простая проверка для валидности email
function isEmail(value) {
  return value.includes('@'); // true, если есть @, иначе false
}
// Пример введённого пользователем email
const email = 'testmail.com';
// Проверяем email с помощью функции isEmail
if (!isEmail(email)) {
  // Если функция вернула false (нет @) — показываем сообщение об ошибке
  showErrorMessage('Введите корректный email');
} else {
  // Если функция вернула true, считаем email корректным
  console.log('Email принят');
}Что ещё почитать
1. MDN Web Docs: управление потоком и обработка ошибок
Объясняет, как работают try…catch, throw, finally и в каких случаях их использовать. Есть примеры синхронного и асинхронного кода, а также рекомендации по стилю.
2. MDN Web Docs: объект Error и его типы
Подробно описывает встроенные типы ошибок: Error, TypeError, SyntaxError, ReferenceError и другие. Рассказывает, как создавать свои классы ошибок и какие свойства доступны.
3. MDN Web Docs: Promise.prototype.catch()
Показывает, как правильно обрабатывать ошибки в промисах. Есть примеры использования .catch() и объяснение, почему его нельзя пропускать.
4. ECMAScript Language Specification (ECMA-262)
Официальная спецификация языка JavaScript. В ней описано поведение исключений на уровне стандарта: как работает throw, как интерпретатор обрабатывает ошибки и какие объекты участвуют в процессе.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!
 Все
                                Все
                             Истории
                                        Истории Дизайн
                                    Дизайн Код
                                    Код Геймдев
                                    Геймдев Бизнес
                                    Бизнес Маркетинг
                                    Маркетинг Управление
                                    Управление Кино
                                    Кино Музыка
                                    Музыка Проектная фотография
                                    Проектная фотография Развитие
                                    Развитие Здоровье
                                    Здоровье Деньги
                                    Деньги Образование
                                    Образование EdTech
                                    EdTech Корп. обучение
                                    Корп. обучение Блог Skillbox
                                    Блог Skillbox Глоссарий
                                        Глоссарий Спецпроекты
                                        Спецпроекты Профориентация
                                        Профориентация 
                                    


 
			 
				 
                                     
                                     
                                     
                                    