three.js 源碼分析之FileLoader

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 );
                //爲什麼不立刻調用onLoad,要在定時器中調用
                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
            //查看下載文件的數據類型,是否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 ];        //
                var isBase64 = !! dataUriRegexResult[ 2 ];
                var data = dataUriRegexResult[ 3 ];

                data = decodeURIComponent( data );

                if ( isBase64 ) data = atob( data );

                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':

                            var parser = new DOMParser();
                            response = parser.parseFromString( data, mimeType );

                            break;

                        case 'json':

                            response = JSON.parse( data );

                            break;

                        default: // 'text' or other

                            response = data;

                            break;

                    }

                    // Wait for next browser tick like standard XMLHttpRequest event dispatching does
                    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
                // 初始化數組
                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 ) {

            this.mimeType = value;
            return this;

        },

        setRequestHeader: function ( value ) {

            this.requestHeader = value;
            return this;

        }

    } );

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章