//记录同一时间段中下载相同文件的标识,相同文件只下载一次
var loading = {};
//封装文件下载类
function FileLoader( manager ) {
//使用默认的文件下载计数类
this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
}
Object.assign( FileLoader.prototype, {
//下载
load: function ( url, onLoad, onProgress, onError ) {
//如果url为空
if ( url === undefined ) url = '';
//拼接url路径
if ( this.path !== undefined ) url = this.path + url;
//修改url
url = this.manager.resolveURL( url );
var scope = this;
//在全局缓冲中查找文件
var cached = Cache.get( url );
//缓冲中找到了
if ( cached !== undefined ) {
//文件下载的计数类开始计数
scope.manager.itemStart( url );
//将下载回调放入到事件队列中,空闲时回调
setTimeout( function () {
//单个文件下载完成
if ( onLoad ) onLoad( cached );
//所有文件其中一个下载完成
scope.manager.itemEnd( url );
}, 0 );
//返回文件
return cached;
}
// Check if request is duplicate
//查看是否有重复的下载项
if ( loading[ url ] !== undefined ) {
//设置同一个文件的回调队列
loading[ url ].push( {
onLoad: onLoad,
onProgress: onProgress,
onError: onError
} );
return;
}
// Check for data: URI
//url中已经带有base64的数据
var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
var dataUriRegexResult = url.match( dataUriRegex );
// Safari can not handle Data URIs through XMLHttpRequest so process manually
//不同浏览器的处理方式不同
if ( dataUriRegexResult ) {
var mimeType = dataUriRegexResult[ 1 ]; //数据的格式 png/jpeg
var isBase64 = !! dataUriRegexResult[ 2 ]; //base64标志
var data = dataUriRegexResult[ 3 ]; //数据
data = decodeURIComponent( data ); //解码数据,支持unicode编码
if ( isBase64 ) data = atob( data ); //解码base64
try {
var response;
var responseType = ( this.responseType || '' ).toLowerCase(); //响应的文件类型
switch ( responseType ) {
case 'arraybuffer': //数组
case 'blob': //二进制文件
var view = new Uint8Array( data.length ); //创建内存
for ( var i = 0; i < data.length; i ++ ) {
view[ i ] = data.charCodeAt( i ); //一个字节一个字节的赋值
}
if ( responseType === 'blob' ) { //如果是二进制
response = new Blob( [ view.buffer ], { type: mimeType } ); //将文件转换为响应格式
} else {
response = view.buffer; //
}
break;
case 'document': //dom文档
var parser = new DOMParser();
response = parser.parseFromString( data, mimeType );
break;
case 'json': //json文件
response = JSON.parse( data );
break;
default: // 'text' or other //文本文件
response = data;
break;
}
// Wait for next browser tick like standard XMLHttpRequest event dispatching does
//仿照XMLHttpRequest 的响应方式
setTimeout( function () {
if ( onLoad ) onLoad( response );
scope.manager.itemEnd( url );
}, 0 );
} catch ( error ) {
// Wait for next browser tick like standard XMLHttpRequest event dispatching does
setTimeout( function () {
if ( onError ) onError( error );
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, 0 );
}
} else {
// Initialise array for duplicate requests
// 初始化这个url 的数组
loading[ url ] = [];
//添加响应函数
loading[ url ].push( {
onLoad: onLoad,
onProgress: onProgress,
onError: onError
} );
//创建请求
var request = new XMLHttpRequest();
//设置请求类型
request.open( 'GET', url, true );
//添加下载完成监听
request.addEventListener( 'load', function ( event ) {
//响应数据添加到缓冲中
var response = this.response;
Cache.add( url, response );
//下载回调
var callbacks = loading[ url ];
delete loading[ url ];
//下载状态
if ( this.status === 200 || this.status === 0 ) {
//本地文件状态为0
// Some browsers return HTTP Status 0 when using non-http protocol
// e.g. 'file://' or 'data://'. Handle as success.
if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
//调用回到
for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
var callback = callbacks[ i ];
if ( callback.onLoad ) callback.onLoad( response );
}
//下载完成
scope.manager.itemEnd( url );
} else {
//下载错误,这是
for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
var callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}
}, false );
//添加下载过程监听
request.addEventListener( 'progress', function ( event ) {
//回调工程处理,主要是百分比
var callbacks = loading[ url ];
for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
var callback = callbacks[ i ];
if ( callback.onProgress ) callback.onProgress( event );
}
}, false );
//添加错误监听
request.addEventListener( 'error', function ( event ) {
var callbacks = loading[ url ];
delete loading[ url ];
for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
var callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
//设置回调错误结束(manager所有文件的下载过程,不是单个文件的下载过程)
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, false );
//添加中断监听
request.addEventListener( 'abort', function ( event ) {
//获取回调
var callbacks = loading[ url ];
//删除
delete loading[ url ];
//遍历回调
for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
var callback = callbacks[ i ];
if ( callback.onError ) callback.onError( event );
}
//设置回调错误结束(manager所有文件的下载过程,不是单个文件的下载过程)
scope.manager.itemError( url );
scope.manager.itemEnd( url );
}, false );
//设置响应类型
if ( this.responseType !== undefined ) request.responseType = this.responseType;
//设置发送cookies
if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;
//设置请求响应解析类型
if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );
//添加其他定义类型
for ( var header in this.requestHeader ) {
request.setRequestHeader( header, this.requestHeader[ header ] );
}
//开始请求
request.send( null );
}
//开始
scope.manager.itemStart( url );
return request;
},
//设置下载路径
setPath: function ( value ) {
this.path = value;
return this;
},
setResponseType: function ( value ) { //设置响应类型
this.responseType = value;
return this;
},
setWithCredentials: function ( value ) { //设置携带的请求验证
this.withCredentials = value;
return this;
},
setMimeType: function ( value ) { //设置mime类型
this.mimeType = value;
return this;
},
setRequestHeader: function ( value ) { //设置请求头
this.requestHeader = value;
return this;
}
} );