Hilo/docs/api-en/code/loader/LoadQueue.js
2019-05-27 11:41:53 +08:00

246 lines
6.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Hilo
* Copyright 2015 alibaba.com
* Licensed under the MIT License
*/
//TODO: 超时timeout失败重连次数maxTries更多的下载器Loader队列暂停恢复等。
/**
* @class LoadQueue is a queue-like loader.
* @mixes EventMixin
* @borrows EventMixin#on as #on
* @borrows EventMixin#off as #off
* @borrows EventMixin#fire as #fire
* @param {Object} source resource that need to be loaded,could be a single object or array resource.
* @module hilo/loader/LoadQueue
* @requires hilo/core/Class
* @requires hilo/event/EventMixin
* @requires hilo/loader/ImageLoader
* @requires hilo/loader/ScriptLoader
* @property {Int} maxConnections the limited concurrent connections. default value 2.
*/
var LoadQueue = Class.create(/** @lends LoadQueue.prototype */{
Mixes: EventMixin,
constructor: function(source){
this._source = [];
this.add(source);
},
maxConnections: 2, //TODO: 应该是每个host的最大连接数。
_source: null,
_loaded: 0,
_connections: 0,
_currentIndex: -1,
/**
* Add desired resource,could be a single object or array resource.
* @param {Object|Array} source ,a single object or array resource. Each resource contains properties like below:
* <ul>
* <li><b>id</b> - resource identifier</li>
* <li><b>src</b> - resource url</li>
* <li><b>type</b> - resource type. By default, we automatically identify resource by file suffix and choose the relevant loader for you</li>
* <li><b>loader</b> - specified resource loader. If you specify this,we abandon choosing loader inside</li>
* <li><b>noCache</b> - a tag that set on or off to prevent cache,implemented by adding timestamp inside</li>
* <li><b>size</b> - predicted resource size, help calculating loading progress</li>
* <li><b>crossOrigin</b> - Whether cross-domain is needed, default is false</li>
* </ul>
* @returns {LoadQueue} 下载队列实例本身。
*/
add: function(source){
var me = this;
if(source){
source = source instanceof Array ? source : [source];
me._source = me._source.concat(source);
}
return me;
},
/**
* get resource object by id or src
* @param {String} specified id or src
* @returns {Object} resource object
*/
get: function(id){
if(id){
var source = this._source;
for(var i = 0; i < source.length; i++){
var item = source[i];
if(item.id === id || item.src === id){
return item;
}
}
}
return null;
},
/**
* get resource object content by id or src
* @param {String} specified id or src
* @returns {Object} resource object content
*/
getContent: function(id){
var item = this.get(id);
return item && item.content;
},
/**
* remove resource object content by id or src
* @param {String} specified id or src
*/
removeContent: function(id){
if(id){
var source = this._source;
for(var i = 0; i < source.length; i++){
var item = source[i];
if(item.id === id || item.src === id){
source.splice(i, 1);
return;
}
}
}
},
/**
* start loading
* @returns {LoadQueue} the loading instance
*/
start: function(){
var me = this;
me._loadNext();
return me;
},
/**
* @private
*/
_loadNext: function(){
var me = this, source = me._source, len = source.length;
//all items loaded
if(me._loaded >= len){
me.fire('complete');
return;
}
if(me._currentIndex < len - 1 && me._connections < me.maxConnections){
var index = ++me._currentIndex;
var item = source[index];
var loader = me._getLoader(item);
if(loader){
var onLoad = loader.onLoad, onError = loader.onError;
loader.onLoad = function(e){
loader.onLoad = onLoad;
loader.onError = onError;
var content = onLoad && onLoad.call(loader, e) || e.target;
me._onItemLoad(index, content);
};
loader.onError = function(e){
loader.onLoad = onLoad;
loader.onError = onError;
onError && onError.call(loader, e);
me._onItemError(index, e);
};
me._connections++;
}
me._loadNext();
loader && loader.load(item);
}
},
/**
* @private
*/
_getLoader: function(item){
var loader = item.loader;
if(loader) return loader;
var type = item.type || getExtension(item.src);
switch(type){
case 'png':
case 'jpg':
case 'jpeg':
case 'gif':
case 'webp':
loader = new ImageLoader();
break;
case 'js':
case 'jsonp':
loader = new ScriptLoader();
break;
}
return loader;
},
/**
* @private
*/
_onItemLoad: function(index, content){
var me = this, item = me._source[index];
item.loaded = true;
item.content = content;
me._connections--;
me._loaded++;
me.fire('load', item);
me._loadNext();
},
/**
* @private
*/
_onItemError: function(index, e){
var me = this, item = me._source[index];
item.error = e;
me._connections--;
me._loaded++;
me.fire('error', item);
me._loadNext();
},
/**
* get resource size, loaded or all.
* @param {Boolean} identify loaded or all resource. default is false, return all resource size. when set true, return loaded resource size.
* @returns {Number} resource size.
*/
getSize: function(loaded){
var size = 0, source = this._source;
for(var i = 0; i < source.length; i++){
var item = source[i];
size += (loaded ? item.loaded && item.size : item.size) || 0;
}
return size;
},
/**
* get loaded resource count
* @returns {Uint} loaded resource count
*/
getLoaded: function(){
return this._loaded;
},
/**
* get all resource count
* @returns {Uint} all resource count
*/
getTotal: function(){
return this._source.length;
}
});
/**
* @private
*/
function getExtension(src){
var extRegExp = /\/?[^/]+\.(\w+)(\?\S+)?$/i, match, extension;
if(match = src.match(extRegExp)){
extension = match[1].toLowerCase();
}
return extension || null;
}