版本基线: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