news 2026/9/29 23:22:11

CesiumJS 初始化、资源加载与避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CesiumJS 初始化、资源加载与避坑

版本基线:CesiumJS 1.133.1(核对日期:2026-08-27);文中通用 API 链接默认指向官方最新版本。

范围说明:本文只介绍 CesiumJS 官方公开 API、浏览器加载规则和通用构建方法,不依赖任何业务组件、私有 SDK 或二次封装。示例中的路径和令牌均为占位值。


1. 初始化结论与推荐顺序

稳定初始化的关键不是“尽快 new Viewer”,而是先确定唯一运行时、固定资源版本、配置资源基路径,再并行启动官方 Provider 请求。地形选择确定后只创建一次 Viewer,并把“Provider 可用”“Viewer 已构造”和“当前视野瓦片已加载”视为三个不同阶段。

阶段

操作

官方 API 或检查点

1. 运行时

全局预构建版或 npm/ESM 二选一;保持 JavaScript 与静态资源版本一致

Cesium.VERSION

2. 资源定位

在首次资源请求前设置基路径,并加载 Widgets 样式

CESIUM_BASE_URL、Cesium.buildModuleUrl()

3. 鉴权

在发起 Cesium ion 请求前写入访问令牌

Cesium.Ion.defaultAccessToken

4. Provider

尽早并行创建地形与影像 Provider

Cesium.createWorldTerrainAsync()、Cesium.createWorldImageryAsync()

5. Viewer

地形方案确定后一次性创建 Viewer

new Cesium.Viewer()、new Cesium.ImageryLayer()

6. 就绪观测

区分 Provider 就绪、Viewer 构造完成与当前视野瓦片完成

tilesLoaded、tileLoadProgressEvent

7. 清理

移除监听并销毁 WebGL、DOM 与事件资源

viewer.isDestroyed()、viewer.destroy()

必须遵守的四条规则

· 同一页面只加载一种 CesiumJS 运行时,不同时使用全局 Cesium.js 和 npm/ESM 运行时。

· Cesium.js、Workers、ThirdParty、Assets、Widgets 与 npm 包必须来自同一发行版本。

· CESIUM_BASE_URL 必须在 CesiumJS 第一次解析 Workers、Assets 或 Widgets 资源之前生效。

· Viewer 销毁后,除 isDestroyed() 外,不再调用该实例的其他属性或方法。


2. 版本与静态资源一致性

本文以 1.133.1 为兼容基线。查阅 API 时优先使用 1.133 版本固定文档,并结合 1.133.1 Release 与 CHANGELOG;不要把 latest 页面的示例未经核对直接套用到旧版本。升级前应在测试环境确认 API、Workers、地形与影像加载行为,并确保 Cesium.js、Workers、ThirdParty、Assets、Widgets 原子发布且版本一致。

运行时需要的目录

· Workers:Web Worker 脚本。缺失或路径错误时,地形解析、几何处理等任务会失败。

· ThirdParty:预构建运行时所需的第三方依赖资源。

· Assets:近似地形高度、纹理等运行时资源。

· Widgets:控件图片、字体与 widgets.css。

避坑:页面能看到地球不代表资源完整。应在浏览器网络面板确认 Workers、Assets、Widgets 等请求没有 404,并通过 Cesium.VERSION 与发布包版本进行核对。


3. 全局预构建版加载

全局预构建版适合通过静态目录直接部署。加载顺序固定为:先声明 CESIUM_BASE_URL,再加载同版本 widgets.css 与 Cesium.js,最后执行应用入口;完整顺序见第 5 节。defer 脚本应保持文档顺序,普通脚本则应放在依赖已加载的位置。

· CESIUM_BASE_URL 可以是绝对路径或相对路径,但必须指向同时包含四类运行时目录的位置。

· 不要依赖脚本下载完成的偶然时序;使用 defer 顺序或在明确的 load 事件后启动。

· 不要重复插入 Cesium.js。重复运行时会导致类型判断、事件对象和资源缓存不一致。


4. npm / ESM 加载

ESM 模式下从 cesium 包导入官方模块,并导入 Widgets 样式。构建产物仍必须能访问 Workers、ThirdParty、Assets、Widgets。基路径应由构建配置定义,或在模块图开始执行前由页面声明。

import * as Cesium from "cesium";
import "cesium/Build/Cesium/Widgets/widgets.css";

console.info(`CesiumJS ${Cesium.VERSION}`);

构建阶段检查

· 固定 cesium 依赖版本;不要让锁文件与部署静态资源来自不同版本。

· 把 Workers、ThirdParty、Assets、Widgets 复制到可公开访问的同一基目录。

· 让 CESIUM_BASE_URL 在生产环境的子路径、CDN 前缀和本地开发路径下都能解析。

· 不要为了调用某个全局扩展而再加载 Cesium.js;需要全局引用时,可明确赋值 globalThis.Cesium = Cesium,但页面仍只能有一个运行时实例。

选择原则:全局预构建版和 ESM 版没有“谁更快”的固定答案。优先选择与现有构建链一致、能保证版本和静态资源原子发布的方式。


5. Cesium ion 与异步 Provider 初始化

Cesium ion 的地形与全球影像需要访问令牌。先设置 Cesium.Ion.defaultAccessToken,再并行调用 Cesium.createWorldTerrainAsync() 与 Cesium.createWorldImageryAsync();第 5 节完整示例统一处理成功、失败与降级路径。

可直接运行的完整示例(CesiumJS 官方 API + Web 标准 API)

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CesiumJS 1.133.1</title>
<script>
window.CESIUM_BASE_URL = "/Cesium/";
</script>
<link rel="stylesheet" href="/Cesium/Widgets/widgets.css" />
<style>
html, body, #cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script src="/Cesium/Cesium.js"></script>
</head>
<body>
<div id="cesiumContainer"></div>
<script>
(async () => {
const Cesium = globalThis.Cesium;
if (!Cesium) throw new Error("CesiumJS runtime is unavailable");
console.info(`CesiumJS ${Cesium.VERSION}`);

Cesium.Ion.defaultAccessToken = "YOUR_ION_TOKEN";

// Web 标准 API:Promise.allSettled()。
// CesiumJS 官方 API:下列 Provider 创建函数与 Provider 类型。
const [terrainResult, imageryResult] = await Promise.allSettled([
Cesium.createWorldTerrainAsync({
requestVertexNormals: false,
requestWaterMask: false,
}),
Cesium.createWorldImageryAsync({
style: Cesium.IonWorldImageryStyle.AERIAL,
}),
]);

if (terrainResult.status === "rejected") {
console.warn("World terrain unavailable", terrainResult.reason);
}
if (imageryResult.status === "rejected") {
console.warn("World imagery unavailable", imageryResult.reason);
}

const terrainProvider =
terrainResult.status === "fulfilled"
? terrainResult.value
: new Cesium.EllipsoidTerrainProvider();

const baseLayer =
imageryResult.status === "fulfilled"
? new Cesium.ImageryLayer(imageryResult.value)
: false;

const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider,
baseLayer,
animation: false,
timeline: false,
baseLayerPicker: false,
geocoder: false,
infoBox: false,
scene3DOnly: true,
});

viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
116.3913,
39.9075,
1500
),
});
})().catch((error) => {
console.error("CesiumJS initialization failed", error);
});
</script>
</body>
</html>

Cesium.createWorldTerrainAsync() 返回 Promise<CesiumTerrainProvider>,Cesium.createWorldImageryAsync() 返回 Promise<IonImageryProvider>。Promise 完成表示 Provider 实例已创建,不表示当前视野的地形和影像瓦片已经加载。Cesium.ImageryLayer.fromProviderAsync() 可接收 ImageryProvider Promise,并在 Provider 就绪后开始渲染,同时通过图层事件报告异步错误。Promise.allSettled() 属于 Web 标准 API。

避免首帧重建:如果最终要使用世界地形,先等待地形 Provider,再创建 Viewer。先显示椭球地形、随后替换为世界地形会造成可见跳变、重复请求和额外场景状态迁移。

Terrain.fromWorldTerrain() 的替代写法

Cesium.Terrain.fromWorldTerrain() 返回 Terrain 实例,可传给 Viewer 的 terrain 选项;仅当 terrainProvider 未设置时才能使用 terrain。Terrain.readyEvent 在 TerrainProvider 创建成功时触发,Terrain.errorEvent 在异步创建出错时触发;readyEvent 触发前不要读取 Terrain.provider。

const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain(),
});


6. Viewer 选项与最小界面

Viewer 默认会启用多种控件和数据源能力。应按产品需要显式配置,避免依赖版本升级后可能变化的默认表现。下表只列出 Viewer 的官方构造选项。

选项

用途

建议

terrainProvider / terrain

初始地形

二选一;需要显式错误处理时使用 terrainProvider

baseLayer

初始底图图层

可传 ImageryLayer;不需要底图时传 false

animation、timeline

时间控制组件

非时间序列场景通常关闭

baseLayerPicker

底图与地形选择器

固定数据源时关闭

geocoder

地理编码搜索

未提供搜索工作流时关闭

homeButton

默认视角按钮

需要自定义首页视角时评估是否保留

sceneModePicker

2D / 3D / Columbus View 切换

纯三维应用可关闭

navigationHelpButton

导航帮助

已有独立帮助入口时关闭

fullscreenButton

全屏控件

容器受布局约束时按需开启

infoBox、selectionIndicator

实体选择反馈

不使用 Entity 选择交互时关闭

scene3DOnly

只创建三维场景所需资源

确定不切换场景模式时设为 true

requestRenderMode

仅在需要时渲染

静态或低频更新场景可开启

maximumRenderTimeChange

时间变化触发渲染的最大间隔

有时钟驱动内容时谨慎调整

useBrowserRecommendedResolution

使用浏览器建议分辨率

高 DPI 设备优先测试该选项

版权与署名:不要通过隐藏 creditContainer、移动署名到不可见区域或覆盖样式来移除 Cesium 及数据提供方的版权信息。任何定制都必须符合 CesiumJS、Cesium ion 和数据提供方的许可与署名条款。


7. 就绪边界、进度与错误

CesiumJS 初始化没有一个能够代表全部完成的单一 Promise。应根据业务真正依赖的阶段选择检查点。相机移动、图层变化或细节层级变化都会产生新的瓦片请求。

边界

含义

可用检查点

运行时可用

CesiumJS 已执行,官方命名空间存在

globalThis.Cesium、Cesium.VERSION

Provider 可用

CesiumTerrainProvider 或 IonImageryProvider 实例已创建

等待 createWorldTerrainAsync() / createWorldImageryAsync()

Viewer 已构造

场景、相机、控件与渲染循环已建立

new Cesium.Viewer() 返回

当前视野瓦片完成

当前视野所需地形和影像队列暂时清空

globe.tilesLoaded、tileLoadProgressEvent

渲染失败

渲染循环捕获到异常

scene.renderError

const removeTileProgress =
viewer.scene.globe.tileLoadProgressEvent.addEventListener((pending) => {
if (pending === 0 && viewer.scene.globe.tilesLoaded) {
console.info("当前视野瓦片已加载");
}
});

const removeRenderError =
viewer.scene.renderError.addEventListener((scene, error) => {
console.error("Cesium render error", error);
});

·tilesLoaded 只描述当前视野中的地形与影像,不代表整个地球或未来视角已缓存。

·tileLoadProgressEvent 的参数是当前瓦片队列长度;相机持续移动时数值可以再次增大。

·renderError 适合记录渲染异常,但不能替代网络请求、令牌状态和 Provider Promise 的错误处理。


8. 相机、容器尺寸与显式渲染

初始相机定位

viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
116.3913,
39.9075,
1500
),
complete: () => console.info("Camera flight completed"),
cancel: () => console.info("Camera flight cancelled"),
});

flyTo() 会启动异步飞行动画,但不返回 Promise。若页面必须区分飞行完成与取消,应使用官方 complete 和 cancel 回调;不要用固定 setTimeout 猜测动画结束时间。

容器尺寸变化:浏览器标准 API 与 CesiumJS 官方 API

ResizeObserver 是浏览器标准 API,不属于 CesiumJS。CesiumJS 1.133 官方文档说明 viewer.resize() 会按需自动调用;仅当 useDefaultRenderLoop 为 false 时不会自动调用。若还要监听容器本身的尺寸变化,可在 ResizeObserver 回调中调用 viewer.resize();开启 requestRenderMode 时,再调用 viewer.scene.requestRender()。

const resizeObserver = new ResizeObserver(() => {
if (!viewer.isDestroyed()) {
viewer.resize();
viewer.scene.requestRender();
}
});
resizeObserver.observe(viewer.container);


9. 性能设置:先测量,再调整

CesiumJS 的性能瓶颈可能来自请求延迟、瓦片解码、地形复杂度、屏幕像素数、实体数量或持续动画。不要用一组固定参数覆盖所有设备。先记录 Cesium.VERSION、视口尺寸、像素比、相机状态和网络条件,再逐项验证。

按需渲染

· requestRenderMode 适合低频更新场景;外部状态改变但 CesiumJS 无法感知时,需要调用 scene.requestRender()。

· maximumRenderTimeChange: Infinity 会停止因时间流逝而自动请求新帧。存在时钟动画、动态材质或时间变化数据时不要盲目设置。

分辨率与帧率

viewer.resolutionScale = 1.0;
viewer.targetFrameRate = 30;

· useBrowserRecommendedResolution 是 Viewer 构造选项;resolutionScale 是 Viewer 属性。两者应结合目标设备实测。

· 降低 resolutionScale 可以减少像素填充压力,但会降低画面清晰度。

· Viewer.targetFrameRate 是 Viewer 属性,仅在 useDefaultRenderLoop 为 true 时生效。未设置时由浏览器 requestAnimationFrame 决定帧率;设置值必须大于 0,且高于底层 requestAnimationFrame 上限不会产生额外效果。


10. 生命周期与完整清理

单页应用切页、组件卸载、容器替换或重新登录时,都应执行对称清理。事件监听、ResizeObserver 和 Viewer 必须由创建它们的生命周期负责释放。

function disposeCesium() {
removeTileProgress();
removeRenderError();
resizeObserver.disconnect();

if (!viewer.isDestroyed()) {
viewer.destroy();
}
}

· Event.addEventListener() 返回的移除函数应保存并调用。

· destroy() 会释放 WebGL 和相关对象;调用后不要继续读取 scene、camera、entities 等属性。

· 需要判断销毁状态时,调用 isDestroyed();这是 destroy() 后唯一允许调用的方法。


11. 常见故障矩阵

现象

优先检查

处理方式

页面空白或 Worker 404

CESIUM_BASE_URL 的设置时机与最终 URL

在运行时加载前设置基路径;确认 Workers 等目录可访问

控件图标或样式缺失

widgets.css 与 Widgets 资源

加载同版本样式,并确认字体、图片请求没有 404

ion 返回 401 / 403

令牌是否在 Provider 请求前设置,权限与域名限制

修正 Ion.defaultAccessToken 与令牌访问范围

地形或影像创建失败

Provider Promise 的拒绝原因

分别捕获 Promise;必要时使用 EllipsoidTerrainProvider 降级

首帧出现地形跳变

是否先创建 Viewer 后替换 terrainProvider

先确定地形 Provider,再创建 Viewer

同页行为不稳定或 instanceof 异常

是否同时加载全局版与 ESM 版

只保留一个运行时,并统一所有导入来源

开发正常、生产资源 404

部署子路径、CDN 前缀与基路径

让 CESIUM_BASE_URL 与实际发布目录一致

加载进度反复变化

相机、视口或图层是否在变化

把进度解释为当前视野队列,不作为全局一次性完成标记

销毁后仍报错

异步回调与事件监听是否仍在访问 Viewer

先移除监听和 Observer,再调用 destroy()

高 DPI 设备卡顿

分辨率、像素比与填充压力

测试 useBrowserRecommendedResolution 与 resolutionScale


12. 验收清单

· 运行时模式唯一:全局预构建版与 npm/ESM 没有同时存在。

· Cesium.VERSION 与 Cesium.js、Workers、ThirdParty、Assets、Widgets 的发行版本一致。

· CESIUM_BASE_URL 在首次 CesiumJS 资源解析前生效,生产子路径下无 404。

· widgets.css 已加载,控件、字体和图标显示正常。

· Ion.defaultAccessToken 在所有 ion Provider 请求前设置,权限遵循最小化原则。

· 地形与影像 Provider 的 Promise 均有明确错误处理或降级策略。

· Viewer 只创建一次;没有为了切换最终地形而重建首帧。

·“Provider 就绪”“Viewer 已构造”“当前视野瓦片完成”没有混为同一个加载状态。

· 相机定位使用 flyTo() 的 complete / cancel 回调,不用固定延时猜测完成。

· 容器尺寸变化后能正确 resize();按需渲染时会 requestRender()。

· 卸载时移除全部监听与 Observer,并在未销毁时调用 viewer.destroy()。

· Cesium 与数据提供方署名可见,符合相关许可条款。


13. 官方参考

以下 API 链接均固定到 CesiumJS 1.133 官方参考文档;latest API Reference 与 Quickstart 仅用于对照和入门。补丁版本差异以 1.133.1 Release 与 CHANGELOG 为准。

· CesiumJS API Reference(latest,仅用于对照):https://cesium.com/learn/cesiumjs/ref-doc/

· Viewer(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Viewer.html

· Ion(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Ion.html

· createWorldTerrainAsync(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/global.html#createWorldTerrainAsync

· createWorldImageryAsync(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/global.html#createWorldImageryAsync

· ImageryLayer(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/ImageryLayer.html

· Terrain(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Terrain.html

· Globe(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Globe.html

· Scene(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Scene.html

· Camera(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Camera.html

· Event(1.133):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/Event.html

· CesiumJS Quickstart(latest,仅用于入门):https://cesium.com/learn/cesiumjs-learn/cesiumjs-quickstart/

· CesiumJS 1.133 API Reference(版本固定):https://cesium.com/downloads/cesiumjs/releases/1.133/Build/Documentation/index.html

· CesiumJS 1.133.1 Release:https://github.com/CesiumGS/cesium/releases/tag/1.133.1

· CesiumJS 1.133.1 CHANGELOG:https://github.com/CesiumGS/cesium/blob/1.133.1/CHANGES.md

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 23:21:03

【AI】Cursor 编辑器使用指南:从 VS Code 迁移到 Agent 工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 23:19:54

CANoe Graphics 窗口配置 TaoToken:统一 Key 接入与 settings.json 骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 23:19:35

【算法考据】《周髀算经》勾股测量与日影观测算法:古代天文几何投影、天球坐标解算与极坐标系统考释

周髀算经讲了什么&#xff1a;勾股测量、日影观测与古代天文数学体系周髀算经讲了什么&#xff1a;勾股测量、日影观测与古代天文数学体系《周髀算经》不是占星秘术&#xff0c;也不是现代意义上的“地平论经典”。它是一部形成过程具有明显层累性的古代天文数学文献&#xff0…

作者头像 李华
网站建设 2026/9/29 23:16:43

【RabbitMQ #6】 | 代码声明队列与交换机

前言&#xff1a; 刚开始学习 RabbitMQ 时&#xff0c;队列、交换机都是在 MQ 的 Web 控制台手动创建。但在实际开发中&#xff0c;业务队列数量很多&#xff0c;不可能每次都手动在 RabbitMQ 控制台创建交换机和队列。推荐在代码中完成队列、交换机、绑定关系的声明&#xff0…

作者头像 李华
网站建设 2026/9/29 23:15:53

遥感图像几何校正实战:用 ENVI 配 TaoToken 打通批量处理流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华