首页
/ three.js LoaderUtils 深度指南:extractUrlBase 与 resolveURL 的源码解析与实战用法

three.js LoaderUtils 深度指南:extractUrlBase 与 resolveURL 的源码解析与实战用法

2026-09-07 20:02:47作者:田桥桑Industrious

three.js 的 LoaderUtils 是一个只提供静态方法的纯工具类,负责在资源加载体系中完成两类高频字符串操作:从文件 URL 中剥离出基准目录、以及把外部资源(纹理、二进制缓冲等)的相对引用解析为最终可请求的完整 URL。在 WebGL/WebGPU 场景中加载 glTF、OBJ、JSON 模型时,LoaderUtils 始终在幕后承担资源定位的职责。读完本文,你将掌握这两个工具方法的确切语义、边界行为,以及它们在 ObjectLoader、GLTFLoader 等真实加载器中的调用方式。

定位与角色:加载器体系中的静态工具箱

在 three.js 的源码布局中,所有内置加载器集中存放于 src/loaders 目录,LoaderUtils 即为其中之一,但与 LoaderFileLoaderObjectLoader 等类实例不同,它不需要 new 出对象,也不挂接 LoadingManager,而是以静态方法的形式暴露两个纯函数工具:

  • extractUrlBase( url ):取 URL 的目录前缀;
  • resolveURL( url, path ):把相对 URL 解析到给定基准路径上。

它的典型协作对象包括:

加载器 源码位置 协作方式
ObjectLoader(核心 JSON 场景加载器) src/loaders/ObjectLoader.js extractUrlBase 推导资源基准目录
GLTFLoader(glTF 格式加载器) examples/jsm/loaders/GLTFLoader.js extractUrlBase + resolveURL 推导 resourcePath
GLTFLoader 内部缓冲/图片加载 examples/jsm/loaders/GLTFLoader.js resolveURL 解析 bufferDef.uri 与纹理源 URI

Constructor:new LoaderUtils()

文档中声明了构造器 new LoaderUtils()。查看 源码类定义 可知,该类的构造器为空实现,且两个方法全部为 static。实际使用中你并不需要实例化它——直接通过 LoaderUtils.extractUrlBase(...) / LoaderUtils.resolveURL(...) 访问即可;刻意调用构造器只会得到一个空对象,没有任何内部状态。

静态方法一:.extractUrlBase( url : string ) : string

语义与实现

该方法“从给定 URL 中提取基准 URL(基目录)”。核心实现位于 src/loaders/LoaderUtils.js

static extractUrlBase( url ) {

	const index = url.lastIndexOf( '/' );

	if ( index === - 1 ) return './';

	return url.slice( 0, index + 1 );

}

逻辑非常直白:找到 URL 中最后一个 / 的位置,返回它(含)之前的全部子串。规则可归纳为:

  1. 若 URL 中不存在任何 /(即裸文件名),返回 './'(当前目录);
  2. 否则返回最后一个 / 之前(含该 /)的子串。

行为示例(与单测一一对应)

test/unit/src/loaders/LoaderUtils.tests.js 中用 QUnit 固化了以下断言:

调用 返回 说明
extractUrlBase( '/path/to/model.glb' ) '/path/to/' 保留尾部斜杠
extractUrlBase( 'model.glb' ) './' 裸文件名,无任何 /
extractUrlBase( '/model.glb' ) '/' 位于根目录,取到根斜杠

注意返回值始终以 /(或 ./)结尾,因此下游可直接把返回字符串与相对资源路径做拼接。

典型调用点:ObjectLoader 的目录推导

ObjectLoader.load 中,加载器通过如下语句为 JSON 场景内引用的外部资源推导基准路径:

const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
this.resourcePath = this.resourcePath || path;

其含义是:当用户没有通过 loader.setPath( ... ) 显式指定基准目录时,就以“被加载 JSON 文件自身所在的目录”作为后续纹理、几何体缓冲等资源的解析起点;只有显式设置了 path 才覆盖该自动推导。第二个加载入口(约在 ObjectLoader.js)重复了相同模式,保证从 parse 或直接 load 两条路径进入时行为一致。而 Loader.setPath 的定义位于基类 src/loaders/Loader.js,默认值为空字符串 ''(见 Loader.js)。

静态方法二:.resolveURL( url : string, path : string ) : string

语义与实现

该方法“将相对 URL 依据给定 path 解析为绝对地址;绝对路径、data URI 与 blob URL 原样返回;非法 URL 返回空字符串”。完整实现见 src/loaders/LoaderUtils.js

static resolveURL( url, path ) {

	// Invalid URL
	if ( typeof url !== 'string' || url === '' ) return '';

	// Host Relative URL
	if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {

		path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );

	}

	// Absolute URL http://,https://,//
	if ( /^(https?:)?\/\//i.test( url ) ) return url;

	// Data URI
	if ( /^data:.*,.*$/i.test( url ) ) return url;

	// Blob URL
	if ( /^blob:.*$/i.test( url ) ) return url;

	// Relative URL
	return path + url;

}

逐分支规则解读

该方法按顺序做六类判断,命中即返回,因此顺序本身也代表优先级:

  1. 非法输入url 不是字符串或为空字符串,直接返回 ''。这是防止拼接出无意义地址的兜底分支。
  2. 主机相对路径(Host Relative):当 pathhttp://https:// 开头、而 url/ 开头时,先把 path 裁到“协议 + 主机名”为止(正则 (^https?:\/\/[^\/]+).* 保留 http(s)://host 部分),使后续拼接得到主机级绝对 URL。
  3. 绝对 URLurlhttp://https:// 或以 // 开头的协议相对地址时,原样返回,不与 path 拼接。
  4. Data URIurl 形如 data:...(以逗号分隔 MIME 与内容),原样返回,便于加载器直接吃内嵌数据。
  5. Blob URLurlblob: 开头时原样返回,支持 URL.createObjectURL 生成的地址。
  6. 其余一律视为相对 URL:执行 path + url 的纯字符串拼接。

一个值得注意的工程细节:这整套逻辑是纯字符串运算,并不依赖浏览器 locationURL/base 标签,因此同样适用于 Web Worker、非 DOM 环境下的加载流程,行为完全可预期。

典型调用点:GLTFLoader 的 resourcePath 推导

glTF 是一种“单文件 + 外部缓冲/纹理引用”的格式,资源定位逻辑集中在 GLTFLoader.load

if ( this.resourcePath !== '' ) {

	resourcePath = this.resourcePath;

} else if ( this.path !== '' ) {

	// 例:path = 'https://my-cdn-server.com/',url = 'assets/models/model.gltf'
	// resourcePath = 'https://my-cdn-server.com/assets/models/'
	// 引用 'model.bin' 将加载自 'https://my-cdn-server.com/assets/models/model.bin'
	const relativeUrl = LoaderUtils.extractUrlBase( url );
	resourcePath = LoaderUtils.resolveURL( relativeUrl, this.path );

} else {

	resourcePath = LoaderUtils.extractUrlBase( url );

}

该处把本文两个工具方法组合使用:先用 extractUrlBase( url ) 取出 glTF 文件所在相对目录(如 assets/models/),再交给 resolveURL 与 CDN 基准 path 合并,最终使 glTF 内声明的 model.bin../textures/texture.png 等相对引用(原注释明确展示可跨目录回退)能命中正确地址。随后在解析缓冲与纹理时再次使用:

  • GLTFLoader.jsloader.load( LoaderUtils.resolveURL( bufferDef.uri, options.path ), ... ),解析 glTF buffers[].uri
  • GLTFLoader.jsLoaderUtils.resolveURL( sourceURI, options.path ),解析图片源 sourceURI

从中可以确认:path 在 GLTFLoader 内部即作为所有外部资源引用的解析基准,这也是官方文档中 resolveURL 第二参数名取 path 的原因。

与 LoadingManager.resolveURL 的区别(避免混淆)

在阅读源码时会发现 LoadingManager 也定义了一个同名方法 resolveURL,但它与 LoaderUtils.resolveURL 无关,二者勿混:

  • LoadingManager.resolveURL 是在发起网络请求前执行的一层钩子:先把 URL 做 String.normalize( 'NFC' )(保证含非 ASCII 字符的 URI 能被正确按 RFC 3987 百分号编码),再交给 setURLModifier 设置的回调改写地址;
  • 它由 FileLoaderImageLoaderImageBitmapLoaderObjectLoader 等在真正发起请求前调用,常用于从 ZIP/拖放文件/Data URI 中改写资源来源;
  • LoaderUtils.resolveURL 是纯静态字符串解析,不触碰任何请求或回调。

两者在管道中的位置也不同:LoaderUtils 负责“把相对路径算成完整路径”,LoadingManager 负责“在请求发出前做最终改写”。

快速参考表

方法 签名 典型返回值
extractUrlBase ( url : string ) : string 最后一个 / 之前的子串;无 / 时返回 './'
resolveURL ( url : string, path : string ) : string 相对输入返回 path + url;绝对/data/blob 原样返回;非法输入返回 ''

小结

LoaderUtils 是 three.js 资源加载链路里不起眼但不可或缺的静态工具类。extractUrlBase 用一次 lastIndexOf('/') 完成“目录剥离”,resolveURL 用一组有序的正则分支完成“相对/绝对/内嵌资源”的判别与拼接。理解它们后,无论阅读 src/loaders/ObjectLoader.js 的目录回退逻辑、还是排查 GLTFLoader 中 CDN 资源 404 的根因,都能更快定位:这类问题十有八九出在 path/resourcePath 是否按预期进入了 extractUrlBaseresolveURL 的输入。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388