ThreeJs入门24-VTKLoader的内部加载过程解析
示例代码采用three.js-r73版本: cdnjs.cloudflare.com/ajax/libs/t…
我们已经实战了VTKLoader来加载我们的VTK模型,那么VTKLoader内部是怎么实现的呢,我们来一探究竟。
VTKLoader构造函数
THREE.VTKLoader = function (manager) { this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager; }; THREE.VTKLoader.prototype = { constructor: THREE.VTKLoader, } 复制代码
THREE.VTKLoader
的原型上设置了构造函数,可以传入
manager
参数,这个参数可以自定义加载管理器如果没有传,就是THREE内部默认的加载管理器
THREE.DefaultLoadingManager
THREE.DefaultLoadingManager
我们来看下默认加载管理器做了什么事
THREE.DefaultLoadingManager = new THREE.LoadingManager(); 复制代码
默认加载管理器是实例化的
THREE.LoadingManager
THREE.LoadingManager
这个函数中定义了一些变量
THREE.LoadingManager = function (onLoad, onProgress, onError) { // 外层 this 别名 var scope = this; var isLoading = false, itemsLoaded = 0, // 代表已经加载字节数 itemsTotal = 0; // 代表加载字节总数 this.onStart = undefined; // 初始化时这个函数没有定义,需要重写 this.onLoad = onLoad; // 加载完成的回调 this.onProgress = onProgress; // 加载进度的回调 this.onError = onError; // 加载错误的回调 .... } 复制代码
需要注意的是
itemsLoaded
和itemsTotal
记录的是字节数整个函数的生命周期是这样的
itemStart 加载之前
onStart 加载载开始的回调
itemEnd 加载结束
onLoad 加载完成的回调
itemStart 和 itemEnd 在每次服务器返回数据时调用
// 加载 url 地址 this.itemStart = function (url) { // 总共加载字节数 itemsTotal++; // 如果没有加载 if (isLoading === false) { // if (scope.onStart !== undefined) { // url 已经加载的数量 总共加载数量 scope.onStart(url, itemsLoaded, itemsTotal); } } // 设置为正在加载 isLoading = true; }; 复制代码
itemStart每次调用会记录总共的加载字节数的总数
如果没有加载,并且有onStart回调,就调用这个方法
把记载状态记为加载中
this.itemEnd = function (url) { // 已经加载字节数 itemsLoaded++; if (scope.onProgress !== undefined) { scope.onProgress(url, itemsLoaded, itemsTotal); } // 已经加载的字节数等于总的字节数 if (itemsLoaded === itemsTotal) { isLoading = false; if (scope.onLoad !== undefined) { // 调用onLoad scope.onLoad(); } } }; 复制代码
itemEnd 会记录已经加载的字节数
如果定义了
onProgress
回调函数,就调用如果已经加载的字节数等于了总的字节数,说明加载完成,调用
onLoad
回调函数
VTKLoader的load方法
介绍完了构造函数,我们来看看VTKLoader的load方法
/** * * @param {*} url url地址 * @param {*} onLoad 加载成功回调 * @param {*} onProgress 加载过程回调 * @param {*} onError 加载错误回调 */ load: function (url, onLoad, onProgress, onError) { var scope = this; // 调用THREE的XHR请求实例,传入了加载管理器 var loader = new THREE.XHRLoader(scope.manager); // 设置cross loader.setCrossOrigin(this.crossOrigin); // 调用加载函数,返回文本数据 loader.load(url, function (text) { // 通过parse解析文本数据,返回geometry onLoad(scope.parse(text)); }, onProgress, onError); }, 复制代码
load方法很简单,主要是传入url地址,然后请求资源,调用对应的回调函数
实例化
THREE.XHRLoader
,请求数据成功之后,返回文本数据,通过parse函数进行解析(下节再详细解释),返回geometry
THREE.XHRLoader
这是THREE内部基于XHR定义的请求加载器
THREE.XHRLoader = function (manager) { this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager; }; THREE.XHRLoader.prototype = { constructor: THREE.XHRLoader, ... } 复制代码
THREE.XHRLoader
的构造函数默认使用的也是THREE.DefaultLoadingManager
主要看下load方法
load: function (url, onLoad, onProgress, onError) { var scope = this; // 获取缓存url的数据 var cached = THREE.Cache.get(url); // 如果有缓存的数据,就直接走缓存缓存 if (cached !== undefined) { if (onLoad) { setTimeout(function () { onLoad(cached); }, 0); } return cached; } // 创建 XHR 的 get 请求 var request = new XMLHttpRequest(); request.open('GET', url, true); // 监听加载状态 request.addEventListener('load', function (event) { // 获取到响应数据 var response = event.target.response; // 把url对应的数据缓存起来 THREE.Cache.add(url, response); // 调用 onLoad回调 返回数据 if (onLoad) onLoad(response); // 调用加载结束方法 scope.manager.itemEnd(url); }, false); // 如果我们定义了 onProgress 回调,监听加载进度 if (onProgress !== undefined) { request.addEventListener('progress', function (event) { onProgress(event); }, false); } // 监听加载错误 request.addEventListener('error', function (event) { // 如果定义了 onError回调 就返回对应的数据 if (onError) onError(event); scope.manager.itemError(url); }, false); // 设置 cross if (this.crossOrigin !== undefined) request.crossOrigin = this.crossOrigin; // 设置响应类型 if (this.responseType !== undefined) request.responseType = this.responseType; // 设置跨域是否携带凭据 if (this.withCredentials !== undefined) request.withCredentials = this.withCredentials; // 发送请求 request.send(null); // 调用 itemStart 生命周期 scope.manager.itemStart(url); return request; } 复制代码
先是获取缓存数据,如果有缓存数据,就直接返回缓存数据
然后通过创建 XHR 的 get 请求,获取数据,把获取的数据缓存起来
调用生命周期方法,完成回调通知
THREE.Cache
three缓存方法实现
THREE.Cache = { enabled: false, // 是否开启缓存 files: {}, // 缓存数据 add: function (key, file) { if (this.enabled === false) return; this.files[key] = file; }, get: function (key) { if (this.enabled === false) return; return this.files[key]; }, remove: function (key) { delete this.files[key]; }, clear: function () { this.files = {}; } }; 复制代码
enabled:是否开启缓存的开关
files:缓存的数据其实是一个局部作用域的object对象
定义了添加(add),获取(get),移除(remove),清空(clear)方法
函数执行流程
核心函数介绍完了,我们来看下整个VTKloader函数的执行流程
总结
这一节我们主要讲了以下内容:
VTKLoader构造函数
THREE.DefaultLoadingManager默认加载器
THREE.LoadingManager加载构造器
THREE.XHRLoader请求loader
THREE.Cache缓存实现
VTKLoader请求资源过程
作者:张雨凡
链接:https://juejin.cn/post/7064374061886865421