1 //TODO: 超时timeout,失败重连次数maxTries,更多的下载器Loader,队列暂停恢复等。 2 3 /** 4 * @class LoadQueue是一个队列下载工具。 5 * @param {Object} source 要下载的资源。可以是单个资源对象或多个资源的数组。 6 * @module hilo/loader/LoadQueue 7 * @requires hilo/core/Class 8 * @requires hilo/event/EventMixin 9 * @property {Int} maxConnections 同时下载的最大连接数。默认为2。 10 */ 11 var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{ 12 Mixes: EventMixin, 13 constructor: function LoadQueue(source){ 14 this._source = []; 15 this.add(source); 16 }, 17 18 maxConnections: 2, //TODO: 应该是每个host的最大连接数。 19 20 _source: null, 21 _loaded: 0, 22 _connections: 0, 23 _currentIndex: -1, 24 25 /** 26 * 增加要下载的资源。可以是单个资源对象或多个资源的数组。 27 * @returns {LoadQueue} 下载队列实例本身。 28 */ 29 add: function(source){ 30 var me = this; 31 if(source){ 32 source = source instanceof Array ? source : [source]; 33 me._source = me._source.concat(source); 34 } 35 return me; 36 }, 37 38 /** 39 * 根据id或src地址获取资源对象。 40 * @returns {Object} 资源对象。 41 */ 42 get: function(id){ 43 if(id){ 44 var source = this._source; 45 for(var i = 0; i < source.length; i++){ 46 var item = source[i]; 47 if(item.id === id || item.src === id){ 48 return item; 49 } 50 } 51 } 52 return null; 53 }, 54 55 /** 56 * 开始下载队列。 57 * @returns {LoadQueue} 下载队列实例本身。 58 */ 59 start: function(){ 60 var me = this; 61 me._loadNext(); 62 return me; 63 }, 64 65 /** 66 * @private 67 */ 68 _loadNext: function(){ 69 var me = this, source = me._source, len = source.length; 70 71 //all items loaded 72 if(me._loaded >= len){ 73 me.fire('complete'); 74 return; 75 } 76 77 if(me._currentIndex < len - 1 && me._connections < me.maxConnections){ 78 var index = ++me._currentIndex; 79 var item = source[index]; 80 var loader = me._getLoader(item); 81 82 if(loader){ 83 var onLoad = loader.onLoad, onError = loader.onError; 84 85 loader.onLoad = function(e){ 86 loader.onLoad = onLoad; 87 loader.onError = onError; 88 var content = onLoad && onLoad.call(loader, e) || e.target; 89 me._onItemLoad(index, content); 90 }; 91 loader.onError = function(e){ 92 loader.onLoad = onLoad; 93 loader.onError = onError; 94 onError && onError.call(loader, e); 95 me._onItemError(index, e); 96 }; 97 loader.load(item); 98 me._connections++; 99 } 100 101 me._loadNext(); 102 } 103 }, 104 105 /** 106 * @private 107 */ 108 _getLoader: function(item){ 109 var me = this, loader = item.loader; 110 if(loader) return loader; 111 112 var type = item.type || getExtension(item.src); 113 114 switch(type){ 115 case 'png': 116 case 'jpg': 117 case 'jpeg': 118 case 'gif': 119 loader = new ImageLoader(); 120 break; 121 case 'js': 122 case 'jsonp': 123 loader = new ScriptLoader(); 124 break; 125 } 126 127 return loader; 128 }, 129 130 /** 131 * @private 132 */ 133 _onItemLoad: function(index, content){ 134 var me = this, item = me._source[index]; 135 item.loaded = true; 136 item.content = content; 137 me._connections--; 138 me._loaded++; 139 me.fire('load', item); 140 me._loadNext(); 141 }, 142 143 /** 144 * @private 145 */ 146 _onItemError: function(index, e){ 147 var me = this, item = me._source[index]; 148 item.error = e; 149 me._connections--; 150 me._loaded++; 151 me.fire('error', item); 152 me._loadNext(); 153 }, 154 155 /** 156 * 获取全部或已下载的资源的字节大小。 157 * @param {Boolean} loaded 指示是已下载的资源还是全部资源。默认为全部。 158 * @returns {Number} 指定资源的字节大小。 159 */ 160 getSize: function(loaded){ 161 var size = 0, source = this._source; 162 for(var i = 0; i < source.length; i++){ 163 var item = source[i]; 164 size += (loaded ? item.loaded && item.size : item.size) || 0; 165 } 166 return size; 167 }, 168 169 /** 170 * 获取已下载的资源数量。 171 * @returns {Uint} 已下载的资源数量。 172 */ 173 getLoaded: function(){ 174 return this._loaded; 175 }, 176 177 /** 178 * 获取所有资源的数量。 179 * @returns {Uint} 所有资源的数量。 180 */ 181 getTotal: function(){ 182 return this._source.length; 183 } 184 185 }); 186 187 /** 188 * @private 189 */ 190 function getExtension(src){ 191 var extRegExp = /\/?[^/]+\.(\w+)/i, match, extension; 192 if(match = src.match(extRegExp)){ 193 extension = match[1].toLowerCase(); 194 } 195 return extension || null; 196 }