Асинхронная загрузка является одной из ключевых особенностей CesiumJS. Практически все операции, связанные с получением данных из внешних источников, выполняются без блокировки основного потока выполнения JavaScript. Благодаря этому интерфейс приложения остается отзывчивым даже при загрузке крупных наборов геопространственных данных, изображений, моделей и тайлов.
В современных версиях CesiumJS активно используются объекты Promise и
синтаксис async/await, что делает работу с асинхронными
операциями более удобной и понятной.
Трехмерные геопространственные приложения работают с большими объемами данных:
Загрузка подобных ресурсов может занимать значительное время. Если бы браузер ожидал завершения каждой операции синхронно, интерфейс приложения постоянно зависал бы.
Асинхронная модель позволяет:
Большинство методов загрузки возвращают объект
Promise.
Пример загрузки GeoJSON:
const promise = Cesium.GeoJsonDataSource.load(
"data/cities.geojson"
);
console.log(promise);
Пока файл загружается, Promise находится в состоянии ожидания.
После успешного завершения операция переходит в состояние fulfilled.
После возникновения ошибки — в состояние rejected.
Классический способ работы с Promise выглядит следующим образом:
Cesium.GeoJsonDataSource.load(
"data/cities.geojson"
).then(function(dataSource) {
viewer.dataSources.add(dataSource);
});
Порядок выполнения:
then().Любая операция загрузки может завершиться ошибкой:
Для обработки подобных ситуаций используется
catch().
Cesium.GeoJsonDataSource.load(
"data/cities.geojson"
)
.then(function(dataSource) {
viewer.dataSources.add(dataSource);
})
.catch(function(error) {
console.error(error);
});
Без обработки ошибок приложение может вести себя непредсказуемо.
Современный подход основан на синтаксисе
async/await.
Тот же пример становится более читаемым:
async function loadCities() {
const dataSource =
await Cesium.GeoJsonDataSource.load(
"data/cities.geojson"
);
viewer.dataSources.add(dataSource);
}
В момент выполнения оператора await функция временно
приостанавливается до получения результата.
Внешний код продолжает работать без блокировок.
GeoJSON является одним из наиболее часто используемых форматов в CesiumJS.
async function loadGeoJson() {
const geojson =
await Cesium.GeoJsonDataSource.load(
"data/roads.geojson"
);
viewer.dataSources.add(geojson);
}
После завершения загрузки на сцене автоматически создаются соответствующие сущности:
Загрузка KML также выполняется асинхронно.
async function loadKml() {
const dataSource =
await Cesium.KmlDataSource.load(
"data/places.kml"
);
viewer.dataSources.add(dataSource);
}
Если документ содержит большое количество объектов, процесс может занимать заметное время.
CZML широко используется для временных геопространственных данных.
async function loadCzml() {
const dataSource =
await Cesium.CzmlDataSource.load(
"data/satellite.czml"
);
viewer.dataSources.add(dataSource);
}
После завершения загрузки Cesium автоматически создает временную шкалу и анимацию объектов.
Наборы 3D Tiles обычно имеют большой размер и практически всегда загружаются постепенно.
async function loadTileset() {
const tileset =
await Cesium.Cesium3DTileset.fromUrl(
"tileset/tileset.json"
);
viewer.scene.primitives.add(
tileset
);
}
Загрузка включает несколько этапов:
tileset.json.Даже после завершения метода fromUrl() отдельные тайлы
продолжают загружаться динамически по мере перемещения камеры.
Трехмерные модели также получают данные через сеть.
async function loadModel() {
const model =
await Cesium.Model.fromGltfAsync({
url: "models/aircraft.glb"
});
viewer.scene.primitives.add(model);
}
Метод возвращает Promise, который завершается после подготовки модели к отображению.
Иногда необходимо дождаться завершения одной операции перед началом другой.
Например, сначала загрузить набор данных, а затем выполнить масштабирование камеры.
async function initializeScene() {
const dataSource =
await Cesium.GeoJsonDataSource.load(
"data/regions.geojson"
);
viewer.dataSources.add(dataSource);
await viewer.flyTo(dataSource);
}
Здесь вторая операция начинается только после завершения первой.
Если данные независимы друг от друга, эффективнее загружать их одновременно.
async function loadData() {
const results = await Promise.all([
Cesium.GeoJsonDataSource.load(
"data/cities.geojson"
),
Cesium.GeoJsonDataSource.load(
"data/rivers.geojson"
),
Cesium.GeoJsonDataSource.load(
"data/roads.geojson"
)
]);
results.forEach(ds => {
viewer.dataSources.add(ds);
});
}
Все запросы отправляются параллельно, что существенно ускоряет загрузку.
Метод Promise.all() завершает работу после успешного
выполнения всех Promise.
const [cities, roads] = await Promise.all([
Cesium.GeoJsonDataSource.load(
"cities.geojson"
),
Cesium.GeoJsonDataSource.load(
"roads.geojson"
)
]);
Если хотя бы один Promise завершится ошибкой, вся операция будет считаться неуспешной.
Иногда необходимо получить результаты всех операций независимо от ошибок.
const results =
await Promise.allSettled([
Cesium.GeoJsonDataSource.load(
"cities.geojson"
),
Cesium.GeoJsonDataSource.load(
"roads.geojson"
)
]);
console.log(results);
Каждый элемент массива содержит информацию:
{
status: "fulfilled",
value: ...
}
или
{
status: "rejected",
reason: ...
}
Такой подход особенно полезен при загрузке большого количества независимых ресурсов.
Во время длительных операций часто отображается индикатор выполнения.
async function loadData() {
loadingElement.style.display = "block";
try {
const dataSource =
await Cesium.GeoJsonDataSource.load(
"large.geojson"
);
viewer.dataSources.add(dataSource);
} finally {
loadingElement.style.display = "none";
}
}
Независимо от результата индикатор будет скрыт.
Многие материалы используют внешние изображения.
const image = await Cesium.Resource.fetchImage({
url: "images/marker.png"
});
Полученное изображение может использоваться:
Класс Resource предоставляет универсальный механизм
работы с удаленными данными.
const resource =
new Cesium.Resource({
url: "data/config.json"
});
Получение JSON:
const json =
await resource.fetchJson();
Получение текста:
const text =
await resource.fetchText();
Получение бинарных данных:
const buffer =
await resource.fetchArrayBuffer();
Часто сервер возвращает настройки или конфигурацию сцены.
async function loadConfig() {
const config =
await Cesium.Resource.fetchJson({
url: "config.json"
});
console.log(config);
}
После получения объекта можно динамически создавать сущности или настраивать визуализацию.
Некоторые компоненты необходимо загрузить до создания сцены.
async function initialize() {
const terrain =
await Cesium.CesiumTerrainProvider.fromIonAssetId(
1
);
const viewer =
new Cesium.Viewer("cesiumContainer", {
terrainProvider: terrain
});
}
Сначала создается провайдер рельефа, затем Viewer.
Современные версии CesiumJS предоставляют асинхронные методы создания провайдеров.
const terrain =
await Cesium.createWorldTerrainAsync();
После завершения загрузки провайдер может быть назначен сцене.
viewer.terrainProvider =
terrain;
Многие ресурсы Cesium ion получают данные через облачную инфраструктуру.
const tileset =
await Cesium.Cesium3DTileset.fromIonAssetId(
12345
);
Последовательность операций включает:
Все этапы выполняются асинхронно.
Наиболее распространенный шаблон для async/await.
async function loadData() {
try {
const dataSource =
await Cesium.GeoJsonDataSource.load(
"data.geojson"
);
viewer.dataSources.add(
dataSource
);
} catch(error) {
console.error(
"Ошибка загрузки:",
error
);
}
}
Такой подход обеспечивает централизованную обработку исключений.
При нестабильном соединении может использоваться механизм повторных запросов.
async function loadWithRetry(
url,
retries = 3
) {
for(let i = 0; i < retries; i++) {
try {
return await Cesium.GeoJsonDataSource.load(
url
);
} catch(error) {
if(i === retries - 1) {
throw error;
}
}
}
}
Подобный механизм полезен для мобильных приложений и удаленных серверов.
Для некоторых типов запросов может использоваться механизм отмены через браузерные API и собственную логику управления запросами.
Типичный сценарий:
Отмена лишних запросов снижает нагрузку на сеть и повышает производительность приложения.
В крупных проектах одновременно могут загружаться:
Распространенная практика заключается в создании централизованного менеджера загрузок.
Пример структуры:
class LoadingManager {
constructor() {
this.pending = 0;
}
start() {
this.pending++;
}
finish() {
this.pending--;
}
get isLoading() {
return this.pending > 0;
}
}
Такой объект позволяет отслеживать текущее состояние приложения и отображать общий индикатор загрузки.
Карты и 3D Tiles используют потоковую модель загрузки.
Особенности:
Благодаря этому даже огромные наборы геопространственных данных могут отображаться в браузере без предварительной загрузки всего объема информации.
Использование async/await вместо длинных цепочек
then()
const ds =
await Cesium.GeoJsonDataSource.load(url);
Обязательная обработка ошибок
try {
...
}
catch(error) {
...
}
Параллельная загрузка независимых ресурсов
await Promise.all([...]);
Отображение состояния загрузки
loading = true;
Минимизация количества последовательных запросов
Каждая лишняя последовательная операция увеличивает время ожидания пользователя.
Разделение логики загрузки и логики отображения
Функции получения данных должны быть независимы от визуализации сцены, что упрощает поддержку и тестирование приложения.
Асинхронная архитектура CesiumJS позволяет эффективно работать с крупными геопространственными наборами данных, облачными сервисами, потоковой передачей 3D Tiles и удаленными ресурсами, сохраняя высокую отзывчивость интерфейса и обеспечивая масштабируемость веб-ГИС любого уровня сложности.