Обработка ошибок

Библиотека Turf.js выполняет геопространственные вычисления над объектами формата GeoJSON. Большинство ошибок возникает не из-за самих алгоритмов, а вследствие передачи некорректных данных, неправильной структуры геометрий, отсутствующих координат или несоответствия типов объектов требованиям конкретной функции.

Ошибки можно разделить на несколько категорий:

  • ошибки входных данных;
  • ошибки структуры GeoJSON;
  • ошибки типов геометрии;
  • ошибки вычислений;
  • ошибки работы с внешними источниками данных;
  • логические ошибки приложения.

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


Использование конструкции try…catch

Большинство исключений Turf.js можно перехватывать стандартными средствами JavaScript.

import * as turf from "@turf/turf";

try {
    const line = turf.lineString([
        [0, 0],
        [10, 10]
    ]);

    const length = turf.length(line);

    console.log(length);
}
catch (error) {
    console.error("Ошибка вычисления:", error.message);
}

Конструкция try...catch является базовым инструментом защиты приложения от неожиданного завершения.


Проверка существования данных

Одной из наиболее распространённых причин ошибок становится обращение к отсутствующим объектам.

Некорректный пример:

const distance = turf.distance(pointA, pointB);

Если одна из переменных содержит undefined, будет выброшено исключение.

Безопасный вариант:

if (pointA && pointB) {
    const distance = turf.distance(pointA, pointB);
}

Дополнительная проверка:

if (!pointA) {
    throw new Error("Точка A отсутствует");
}

if (!pointB) {
    throw new Error("Точка B отсутствует");
}

Валидация координат

Координаты должны представлять собой массив чисел.

Правильный формат:

[37.6176, 55.7558]

Неправильные варианты:

["37.6176", "55.7558"]

[37.6176]

null

Проверка:

function validateCoordinate(coord) {
    return (
        Array.isArray(coord) &&
        coord.length === 2 &&
        typeof coord[0] === "number" &&
        typeof coord[1] === "number"
    );
}

Использование:

if (!validateCoordinate(coords)) {
    throw new Error("Некорректные координаты");
}

Проверка диапазона координат

Даже если координаты имеют правильный тип, они могут выходить за допустимые пределы.

Допустимые значения:

Параметр Диапазон
Долгота -180 … 180
Широта -90 … 90

Проверка:

function validateLongitude(value) {
    return value >= -180 && value <= 180;
}

function validateLatitude(value) {
    return value >= -90 && value <= 90;
}

Комплексная проверка:

function validatePosition([lng, lat]) {
    return (
        validateLongitude(lng) &&
        validateLatitude(lat)
    );
}

Контроль типов геометрии

Многие функции Turf.js работают только с определёнными типами объектов.

Например, функция length() ожидает линейную геометрию.

Ошибка:

const polygon = turf.polygon([
    [
        [0, 0],
        [5, 0],
        [5, 5],
        [0, 5],
        [0, 0]
    ]
]);

turf.length(polygon);

Перед вычислением желательно проверять тип.

if (geometry.geometry.type !== "LineString") {
    throw new Error(
        "Ожидается геометрия типа LineString"
    );
}

Проверка структуры GeoJSON

GeoJSON должен соответствовать официальной спецификации.

Пример корректного объекта:

{
    "type": "Feature",
    "geometry": {
        "type": "Point",
        "coordinates": [30, 10]
    },
    "properties": {}
}

Проверка структуры:

function isFeature(obj) {
    return (
        obj &&
        obj.type === "Feature" &&
        obj.geometry
    );
}

Использование:

if (!isFeature(feature)) {
    throw new Error("Некорректный GeoJSON Feature");
}

Проверка типа FeatureCollection

Некоторые операции требуют коллекцию объектов.

if (data.type !== "FeatureCollection") {
    throw new Error(
        "Ожидается FeatureCollection"
    );
}

Дополнительно:

if (!Array.isArray(data.features)) {
    throw new Error(
        "Поле features должно быть массивом"
    );
}

Обработка пустых коллекций

Пустая коллекция часто приводит к неожиданным результатам.

const collection = turf.featureCollection([]);

Проверка:

if (collection.features.length === 0) {
    console.warn(
        "Коллекция не содержит объектов"
    );
}

Возможен возврат значения по умолчанию:

if (!collection.features.length) {
    return null;
}

Обработка ошибок при буферизации

Функция buffer() особенно чувствительна к качеству входных данных.

try {
    const result = turf.buffer(feature, 5, {
        units: "kilometers"
    });

    return result;
}
catch (error) {
    console.error(
        "Ошибка построения буфера:",
        error.message
    );
}

Типичные причины ошибок:

  • повреждённая геометрия;
  • самопересекающийся полигон;
  • отсутствующие координаты;
  • неверный тип объекта.

Защита операций пересечения

Операции пересечения геометрий нередко завершаются ошибками на сложных полигонах.

try {
    const intersection =
        turf.intersect(
            turf.featureCollection([
                polygon1,
                polygon2
            ])
        );

    return intersection;
}
catch (error) {
    console.error(
        "Ошибка пересечения:",
        error.message
    );
}

Особенно важно контролировать:

  • замкнутость контуров;
  • корректность колец полигона;
  • отсутствие дублирующихся вершин.

Обработка ошибок объединения полигонов

Операция объединения также может завершиться исключением.

try {
    const merged =
        turf.union(
            turf.featureCollection([
                polygon1,
                polygon2
            ])
        );

    return merged;
}
catch (error) {
    console.error(
        "Ошибка объединения:",
        error.message
    );
}

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


Проверка замкнутости полигона

Контур полигона должен начинаться и заканчиваться одной и той же координатой.

Корректный пример:

[
    [0, 0],
    [10, 0],
    [10, 10],
    [0, 10],
    [0, 0]
]

Проверка:

function isClosedRing(ring) {
    const first = ring[0];
    const last = ring[ring.length - 1];

    return (
        first[0] === last[0] &&
        first[1] === last[1]
    );
}

Использование:

if (!isClosedRing(ring)) {
    throw new Error(
        "Контур полигона не замкнут"
    );
}

Проверка минимального количества вершин

Для полигона требуется минимум четыре координаты, включая повтор первой точки.

Проверка:

function hasMinimumVertices(ring) {
    return ring.length >= 4;
}

Пример:

if (!hasMinimumVertices(ring)) {
    throw new Error(
        "Недостаточно вершин для полигона"
    );
}

Логирование ошибок

При разработке важно сохранять подробную информацию об ошибках.

try {
    const area = turf.area(polygon);
}
catch (error) {
    console.error({
        message: error.message,
        stack: error.stack,
        timestamp: new Date()
    });
}

Такой подход существенно облегчает поиск проблем.


Централизованная функция обработки ошибок

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

function handleGeoError(error, context) {
    console.error({
        context,
        message: error.message,
        stack: error.stack,
        time: new Date().toISOString()
    });
}

Использование:

try {
    const center = turf.center(feature);
}
catch (error) {
    handleGeoError(error, "center");
}

Создание безопасных обёрток

Распространённая практика — создание функций, скрывающих обработку исключений.

function safeArea(feature) {
    try {
        return turf.area(feature);
    }
    catch (error) {
        console.error(error);

        return 0;
    }
}

Применение:

const area = safeArea(polygon);

Программа продолжит работу даже при возникновении ошибки.


Возврат объекта результата

Вместо выбрасывания исключений можно использовать специальный объект результата.

function safeLength(line) {
    try {
        return {
            success: true,
            value: turf.length(line)
        };
    }
    catch (error) {
        return {
            success: false,
            error: error.message
        };
    }
}

Использование:

const result = safeLength(line);

if (result.success) {
    console.log(result.value);
}
else {
    console.error(result.error);
}

Подобный подход часто применяется в корпоративных геоинформационных системах.


Асинхронная обработка ошибок

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

async function loadAndProcess() {
    try {
        const response =
            await fetch("/data.geojson");

        const geojson =
            await response.json();

        return turf.bbox(geojson);
    }
    catch (error) {
        console.error(
            "Ошибка загрузки или обработки:",
            error.message
        );
    }
}

Проверка ответа сервера

Недостаточно перехватывать исключения JavaScript. Необходимо контролировать статус ответа.

async function loadGeoJSON() {
    const response =
        await fetch("/data.geojson");

    if (!response.ok) {
        throw new Error(
            `HTTP ${response.status}`
        );
    }

    return response.json();
}

Использование:

try {
    const data = await loadGeoJSON();
}
catch (error) {
    console.error(error.message);
}

Пользовательские ошибки

Для более точной диагностики удобно создавать собственные классы исключений.

class GeoValidationError
    extends Error {

    constructor(message) {
        super(message);
        this.name =
            "GeoValidationError";
    }
}

Использование:

if (!feature.geometry) {
    throw new GeoValidationError(
        "Геометрия отсутствует"
    );
}

Обработка:

try {
    processFeature(feature);
}
catch (error) {
    if (
        error instanceof
        GeoValidationError
    ) {
        console.error(
            "Ошибка данных:",
            error.message
        );
    }
}

Проверка данных перед вызовом Turf.js

Наиболее эффективная стратегия предотвращения ошибок заключается в предварительной валидации данных.

Последовательность проверки обычно включает:

  1. Проверку существования объекта.
  2. Проверку типа GeoJSON.
  3. Проверку структуры геометрии.
  4. Проверку координат.
  5. Проверку диапазонов широты и долготы.
  6. Проверку замкнутости полигонов.
  7. Проверку количества вершин.
  8. Проверку соответствия типа объекта вызываемой функции.

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