Библиотека Turf.js выполняет геопространственные вычисления над объектами формата GeoJSON. Большинство ошибок возникает не из-за самих алгоритмов, а вследствие передачи некорректных данных, неправильной структуры геометрий, отсутствующих координат или несоответствия типов объектов требованиям конкретной функции.
Ошибки можно разделить на несколько категорий:
Грамотная обработка исключений позволяет избежать аварийного завершения программы и обеспечивает предсказуемое поведение геоинформационных систем.
Большинство исключений 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 должен соответствовать официальной спецификации.
Пример корректного объекта:
{
"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");
}
Некоторые операции требуют коллекцию объектов.
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 и значительно повышает надёжность геопространственных приложений.