Механизм получения данных в OpenLayers строится вокруг асинхронных источников, где Fetch API выступает базовым инструментом для взаимодействия с сервером. Основная идея заключается в разделении ответственности: карта и слои не знают ничего о транспортном уровне, а получают уже подготовленные геоданные через функции загрузки.
Fetch API используется векторными источниками, пользовательскими загрузчиками, а также в интеграции с REST-сервисами, выдающими GeoJSON, TopoJSON, MVT или произвольные JSON-структуры.
Fetch представляет собой Promise-ориентированный интерфейс
HTTP-запросов. В контексте OpenLayers он применяется внутри загрузчиков
источников (loader), где результат преобразуется в объекты
геометрии.
Типовой сценарий включает:
fetch('https://example.com/data.geojson')
.then(response => response.json())
.then(data => {
// обработка GeoJSON
});
В OpenLayers этот процесс чаще инкапсулируется внутри
ol/source/Vector, где fetch используется как низкоуровневый
транспорт.
Наиболее гибкая схема загрузки данных реализуется через
ol/source/Vector с кастомной функцией
loader.
import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
const source = new VectorSource({
loader: function(extent, resolution, projection) {
fetch(`https://example.com/api/features?bbox=${extent.join(',')}`)
.then(response => response.json())
.then(json => {
const features = new GeoJSON().readFeatures(json, {
featureProjection: projection
});
source.addFeatures(features);
});
}
});
Ключевой элемент архитектуры заключается в том, что загрузка привязана к текущему экстенту карты. Это позволяет реализовать динамическую подгрузку данных по области видимости.
Extent передается в loader как массив координат
[minX, minY, maxX, maxY]. Этот диапазон используется для
серверной фильтрации.
Часто применяется следующая схема:
const bbox = extent.join(',');
const url = new URL('https://example.com/features');
url.searchParams.set('bbox', bbox);
url.searchParams.set('srid', projection.getCode());
fetch(url.toString())
Такой подход снижает объем передаваемых данных и ускоряет отрисовку.
При интерактивном перемещении карты множество запросов могут
устаревать. Для их контроля используется
AbortController.
let controller;
const source = new VectorSource({
loader: function(extent, resolution, projection) {
if (controller) {
controller.abort();
}
controller = new AbortController();
fetch('https://example.com/data', {
signal: controller.signal
})
.then(r => r.json())
.then(json => {
const features = new GeoJSON().readFeatures(json, {
featureProjection: projection
});
source.addFeatures(features);
})
.catch(e => {
if (e.name !== 'AbortError') {
console.error(e);
}
});
}
});
Такой механизм предотвращает накопление устаревших сетевых операций и снижает нагрузку на клиент.
Сетевые данные требуют строгой обработки ошибок:
Fetch не выбрасывает ошибку на HTTP-статус, поэтому проверка выполняется вручную:
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
Для повышения устойчивости применяется повторная отправка запросов:
function fetchWithRetry(url, retries = 3) {
return fetch(url).then(response => {
if (!response.ok && retries > 0) {
return fetchWithRetry(url, retries - 1);
}
return response.json();
});
}
После получения данных fetch не участвует в дальнейшей логике. Его результат передается в парсеры:
ol/format/GeoJSONol/format/TopoJSONol/format/WKTGeoJSON остается наиболее распространенным форматом.
const format = new GeoJSON();
fetch(url)
.then(r => r.json())
.then(json => {
const features = format.readFeatures(json, {
featureProjection: 'EPSG:3857'
});
});
Преобразование проекций является обязательным этапом при работе с веб-картографией.
Fetch позволяет задавать HTTP-заголовки, что используется для доступа к защищенным API:
fetch('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer TOKEN',
'Accept': 'application/json'
}
})
В OpenLayers это особенно важно при работе с приватными геосервисами, где каждый запрос должен содержать токен доступа.
При работе с картой часто повторяются идентичные запросы. Оптимизация включает:
Простейшая форма кэша:
const cache = new Map();
function cachedFetch(url) {
if (cache.has(url)) {
return Promise.resolve(cache.get(url));
}
return fetch(url)
.then(r => r.json())
.then(data => {
cache.set(url, data);
return data;
});
}
При больших объемах геоданных загрузка может происходить по частям.
Хотя Fetch API поддерживает streaming, OpenLayers чаще работает с
полными JSON-ответами, однако возможно использование потоковой обработки
через ReadableStream.
fetch(url).then(response => {
const reader = response.body.getReader();
// обработка чанков
});
Такой подход применяется при нестандартных API или бинарных форматах.
REST-сервисы часто ограничивают размер ответа. Векторный источник может реализовать постраничную загрузку:
function loadPage(page) {
return fetch(`https://api.example.com/features?page=${page}`)
.then(r => r.json());
}
let page = 1;
function loader(extent, resolution, projection) {
loadPage(page).then(json => {
const features = new GeoJSON().readFeatures(json, {
featureProjection: projection
});
source.addFeatures(features);
page += 1;
});
}
После получения данных через fetch часто выполняется преобразование координат:
OpenLayers выполняет это через featureProjection, но
иногда требуется предварительная трансформация на уровне данных.
При массовой загрузке данных используется ограничение параллелизма:
const urls = [...];
async function loadAll() {
for (const url of urls) {
const res = await fetch(url);
const json = await res.json();
}
}
Для ускорения применяется Promise.all, однако это
увеличивает нагрузку:
Promise.all(urls.map(u => fetch(u).then(r => r.json())));
Выбор стратегии зависит от объема данных и ограничений сервера.
Fetch используется не только для векторов. В тайловых слоях он участвует в загрузке бинарных тайлов и метаданных.
Пример кастомного tile load function:
tileLoadFunction: function(tile, src) {
fetch(src)
.then(response => response.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
tile.getImage().src = url;
});
}
Fetch становится связующим звеном между серверной геоаналитикой и клиентской визуализацией. Сервер может возвращать:
OpenLayers в этом случае выполняет роль визуального рендера, а fetch — транспорта данных между слоями системы.