Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Коды ошибок JS: Обработка ошибок

Подход, при котором мы возвращаем либо false, либо данные, подразумевает, что у нас есть два состояния. Но это не всегда так.

Например, если мы возвращаем ошибку файловой системы, то обычно хотим знать, что за ошибка произошла. Например, в файловых системах в UNIXO количество ошибок превышает 100:

#define EPERM    1  /* Operation not permitted */
#define ENOENT   2  /* No such file or directory */
#define ESRCH    3  /* No such process */
#define EINTR    4  /* Interrupted system call */
#define EIO      5  /* I/O error */
#define ENXIO    6  /* No such device or address */
#define E2BIG    7  /* Arg list too long */
#define ENOEXEC  8  /* Exec format error */
#define EBADF    9  /* Bad file number */
#define ECHILD  10  /* No child processes */

Самостоятельно пытаться догадаться, что произошло, — не лучшая идея. Так мы не сможем далеко продвинуться при работе с программой.

В этом случае появляется вопрос, как действовать — как возвращать результат. Один из самых простых вариантов — это коды возврата.

Коды возврата

Возврат ошибки связан с тем, что мы возвращаем не просто false или undefined. Мы возвращаем некоторое число. Оно говорит о том, какая ошибка произошла. Это работает так:

// Вызываем команду, например, удаление директории, и получаем результат
const result = files.rmdir(path);

// Проверяем, является ли результат частью списка ошибок. Перечисляем возможные варианты
if ([/* errors list */].includes(result)) {
  // error
} else {
  // success
}

В итоге мы узнаем, входит ли результат в список ошибок. Если всё хорошо, то мы продолжаем работать и используем тот же результат.

Проблема в том, что результат иногда может быть числовым. Тогда нам нужно выбрать лист ошибок, чтобы нормальное значение не попадало в него.

В итоге нам постоянно придется делать такие проверки — проверять большое количество возможных возвратов. Такой процесс нужно упрощать.

Возврат результата в СИ

В Си принят следующий подход возврата результата:

#include <stdio.h>
#include <errno.h>

extern int errno;

int main () {
  FILE * fp;
  # Открываем файл на чтение
  fp = fopen("filedoesnotexist.txt", "rb");
  # Делаем проверку
  if (fp == NULL) { // Value of errno is: 2
    # Если указатель равен нулю, то пишем, что произошла ошибка
    fprintf(stderr, "Value of errno: %d\n", errno);
  } else {
    fclose (fp);
  }
  return 0;
}

Ошибка записывается в глобальную переменную, которая называется errno. И там, например, будет цифра 2, которая означает, что всё плохо.

Здесь мы убеждаемся, что у нас нет адекватного результата. Но по сути идет глобальное изменение среды. А глобальные переменные — это не вариант, особенно, в современных языках.

Возврат результата в Golang

Рассмотрим более продвинутый способ. Этот тот же способ, что и в СИ, но улучшенный. Он называется Golang Style.

Golang — это современный язык, который избавляет от глобальных переменных.

Смотрим пример:

package main
import (
  "fmt"
  "io"
  "io/ioutil"
)

func main() {
  // Возращается два значения: dat — данные, err — ошибка
  dat, err := ioutil.ReadFile("/tmp/dat")
  // Проверяем, равна ли ошибка nil
  if err != nil {
    fmt.Println(err.Error())
  }
  fmt.Print(string(dat))
}

Если ошибка не равна nil, то ошибки нет, и всё хорошо. Если равна nil, то мы обрабатываем ее.

Это фактически такой же подход как в CИ. Только здесь нет глобальной переменной, которая постоянно меняется. Каждая функция возвращает свой результат выполнения. Так мы двигаемся вниз по вызовам и можем строить программу.

Возврат результата в JavaScript

В JavaScript можно использовать такой же подход. Это рабочая схема, которая основана на Destructuring. У нее есть определенные недостатки, которые мы разберем в следующем уроке.

Рассмотрим пример:

// Делаем чтение, описываем данные и ошибку
const [data, err] = files.readFileSync('/unknown');
if (err === null) {
  // do something with data
} else {
  // handle error
}

// return [null, errors.code.ENOENT];

Если ошибка равна null, то делаем все что хотим, если нет, то обрабатываем ошибку.

Выводы

В этом уроке мы разобрали коды возвратов. Мы рассмотрели, как выглядит результат возврата в СИ, Go и JavaScript. Также узнали, как реализовать механизм возврата кодов, чтобы они сигнализировали об определенных типах ошибок.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»