This article describes how to use the JavaScript front-end image loading manager imagepool. For more information, see
Preface
Imagepool is a JS tool for managing image loading. It allows you to control the number of concurrently Loaded Images.
For image loading, the original method is to directly write an img tag, for example :.
After continuous optimization, the scheme of image loading delay occurs. This time, the image URL is not directly written in the src attribute, but in a certain attribute, for example :. In this way, the browser will not automatically load images. When an appropriate time needs to be loaded, the url in the data-src attribute will be put in the src attribute of the img Tag using js, or after reading the url, use js to load the image. After loading, set the src attribute to display the image.
This seems to have been well controlled, but there are still problems.
Although only a part of images can be loaded, this part of images may still be a relatively large order of magnitude.
This is no big deal for the PC end, but for the mobile end, the number of concurrent image loading is too large, and it is very likely to cause the application to crash.
Therefore, we urgently need an image buffer mechanism to control the concurrency of image loading. Similar to the back-end database connection pool, it does not create too many connections, and can fully reuse each connection.
So far, imagepool is born.
Poor schematic
Instructions for use
First, initialize the connection pool:
Var imagepool = initImagePool (5 );
InitImagePool is a global method that can be directly used anywhere. Create a connection pool and specify the maximum number of connections in the connection pool. Optional. The default value is 5.
On the same page, multiple calls to initImagePool will return the same core instance, which is always the first. For example:
The Code is as follows:
Var imagepool1 = initImagePool (3 );
Var imagepool2 = initImagePool (7 );
At this time, the maximum number of connections between imagepool1 and imagepool2 is 3, and the same core instance is used internally. Note that the internal core is the same, not to say imagepool1 = imagepool2.
After initialization, you can load images with confidence.
The simplest call method is as follows:
The Code is as follows:
Var imagepool = initImagePool (10 );
Imagepool. load ("image url ",{
Success: function (src ){
Console. log ("success:" + src );
},
Error: function (src ){
Console. log ("error:" + src );
}
});
Call the load method directly on the instance.
The load method has two parameters. The first parameter is the image url to be loaded, and the second parameter is a variety of options, including successful and failed Callbacks. The image url will be input during callback.
In this way, only one image can be input. Therefore, it can also be written as follows:
The Code is as follows:
Var imagepool = initImagePool (10 );
Imagepool. load (["image 1url", "image 2url"], {
Success: function (src ){
Console. log ("success:" + src );
},
Error: function (src ){
Console. log ("error:" + src );
}
});
You can input multiple images by passing in an image url array.
If an image is successfully loaded (or fails), the success (or error) method is called and the corresponding image url is input.
However, sometimes we do not need such frequent Callbacks. We can pass in an image url array. When all the images in this array are processed, we can call back.
You only need to add one option:
The Code is as follows:
Var imagepool = initImagePool (10 );
Imagepool. load (["image 1url", "image 2url"], {
Success: function (sArray, eArray, count ){
Console. log ("sArray:" + sArray );
Console. log ("eArray:" + eArray );
Console. log ("count:" + count );
},
Error: function (src ){
Console. log ("error:" + src );
},
Once: true
});
By adding a once attribute in the option and setting it to true, You can implement only one callback.
This callback must call back the success method, and the error method is ignored.
In this case, the success method is called back, instead of passing in an image url parameter. Instead, three parameters are input: Successful url array, failed url array, and total number of processed images.
In addition, there is another way to get the internal status of the Connection Pool:
The Code is as follows:
Var imagepool = initImagePool (10 );
Console. log (imagepool.info ());
Call the info method to obtain the internal status of the connection pool at the current time. The data structure is as follows:
Object. task. count number of tasks to be processed in the connection pool
Object. thread. count maximum number of connections in the connection pool
Number of idle connections in the Object. thread. free connection pool
We recommend that you do not call this method frequently.
It should be noted that if the image fails to be loaded, a maximum of three attempts will be made. If the image fails to be loaded, the error method will be called back. The number of attempts can be modified in the source code.
At the end of this article, you can push images to the connection pool without worrying about excessive concurrency. The imagepool will load these images for you.
In the end, it must be noted that the imagepool does not theoretically reduce the image loading speed, but is just a gentle loading.
Source code
The Code is as follows:
(Function (exports ){
// Singleton
Var instance = null;
Var emptyFn = function (){};
// Initial Default Configuration
Var config_default = {
// Number of threads in the thread pool
Thread: 5,
// Number of Retries for failed image loading
// Retry twice, and add the original one, total is 3
"Try": 2
};
// Tool
Var _ helpers = {
// Set dom attributes
SetAttr: (function (){
Var img = new Image ();
// Determine whether the browser supports HTML5 dataset
If (img. dataset ){
Return function (dom, name, value ){
Dom. dataset [name] = value;
Return value;
};
} Else {
Return function (dom, name, value ){
Dom. setAttribute ("data-" + name, value );
Return value;
};
}
}()),
// Get dom attributes
GetAttr: (function (){
Var img = new Image ();
// Determine whether the browser supports HTML5 dataset
If (img. dataset ){
Return function (dom, name ){
Return dom. dataset [name];
};
} Else {
Return function (dom, name ){
Return dom. getAttribute ("data-" + name );
};
}
}())
};
/**
* Constructor
* @ Param max the maximum number of connections. Value.
*/
Function ImagePool (max ){
// Maximum number of concurrent jobs
This. max = max | config_default.thread;
This. linkHead = null;
This. linkNode = null;
// Load the pool
// [{Img: dom, free: true, node: node}]
// Node
// {Src: "", options: {success: "fn", error: "fn", once: true}, try: 0}
This. pool = [];
}
/**
* Initialization
*/
ImagePool. prototype. initPool = function (){
Var I, img, obj, _ s;
_ S = this;
For (I = 0; I <this. max; I ++ ){
Obj = {};
Img = new Image ();
_ Helpers. setAttr (img, "id", I );
Img. onload = function (){
Var id, src;
// Callback
// _ S. getNode (this). options. success. call (null, this. src );
_ S. notice (_ s. getNode (this), "success", this. src );
// Process the task
_S.exe cuteLink (this );
};
Img. onerror = function (e ){
Var node = _ s. getNode (this );
// Determine the number of attempts
If (node. try <config_default.try ){
Node. try = node. try + 1;
// Append it to the end of the task linked list again
_ S. appendNode (_ s. createNode (node. src, node. options, node. notice, node. group, node. try ));
} Else {
// Error callback
// Node. options. error. call (null, this. src );
_ S. notice (node, "error", this. src );
}
// Process the task
_S.exe cuteLink (this );
};
Obj. img = img;
Obj. free = true;
This. pool. push (obj );
}
};
/**
* Callback Encapsulation
* @ Param node. Object.
* @ Param status. String. Value Options: success (successful) | error (failed)
* @ Param src: Specifies the image path. String.
*/
ImagePool. prototype. notice = function (node, status, src ){
Node. notice (status, src );
};
/**
* Process linked list tasks
* @ Param dom the dom object of the image. Object.
*/
ImagePool.prototype.exe cuteLink = function (dom ){
// Determine whether the linked list has nodes
If (this. linkHead ){
// Load the next image
This. setSrc (dom, this. linkHead );
// Remove the linked list Header
This. shiftNode ();
} Else {
// Set the status to idle
This. status (dom, true );
}
};
/**
* Getting idle "Threads"
*/
ImagePool. prototype. getFree = function (){
Var length, I;
For (I = 0, length = this. pool. length; I <length; I ++ ){
If (this. pool [I]. free ){
Return this. pool [I];
}
}
Return null;
};
/**
* Encapsulate src attribute settings
* Changing the src attribute is equivalent to loading images, so the operation is encapsulated.
* @ Param dom the dom object of the image. Object.
* @ Param node. Object.
*/
ImagePool. prototype. setSrc = function (dom, node ){
// Set the "Thread" in the pool to non-idle.
This. status (dom, false );
// Associate nodes
This. setNode (dom, node );
// Load the image
Dom. src = node. src;
};
/**
* Update the "Thread" status in the pool.
* @ Param dom the dom object of the image. Object.
* @ Param status. Boolean. Value Options: true (idle) | false (non-idle)
*/
ImagePool. prototype. status = function (dom, status ){
Var id = _ helpers. getAttr (dom, "id ");
This. pool [id]. free = status;
// Idle state to clear associated nodes
If (status ){
This. pool [id]. node = null;
}
};
/**
* Update the associated node of the "Thread" in the pool.
* @ Param dom the dom object of the image. Object.
* @ Param node. Object.
*/
ImagePool. prototype. setNode = function (dom, node ){
Var id = _ helpers. getAttr (dom, "id ");
This. pool [id]. node = node;
Return this. pool [id]. node === node;
};
/**
* Obtain the associated node of the "Thread" in the pool.
* @ Param dom the dom object of the image. Object.
*/
ImagePool. prototype. getNode = function (dom ){
Var id = _ helpers. getAttr (dom, "id ");
Return this. pool [id]. node;
};
/**
* External interface: loading Images
* @ Param src can be a src string or an array of src strings.
* @ Param options User-Defined parameters. Including success callback, error callback, And once identity.
*/
ImagePool. prototype. load = function (src, options ){
Var srcs = [],
Free = null,
Length = 0,
I = 0,
// Only initialize the callback policy once
Notice = (function (){
If (options. once ){
Return function (status, src ){
Var g = this. group,
O = this. options;
// Record
G [status]. push (src );
// Determine whether all the reorganization has been completed
If (g. success. length + g. error. length = g. count ){
// Asynchronous
// It is actually executed separately as another task to prevent the image loading speed from being affected by the long execution time of the callback function
SetTimeout (function (){
O. success. call (null, g. success, g. error, g. count );
}, 1 );
}
};
} Else {
Return function (status, src ){
Var o = this. options;
// Direct callback
SetTimeout (function (){
O [status]. call (null, src );
}, 1 );
};
}
}()),
Group = {
Count: 0,
Success: [],
Error: []
},
Node = null;
Options = options | {};
Options. success = options. success | emptyFn;
Options. error = options. error | emptyFn;
Srcs = srcs. concat (src );
// Set the number of group elements
Group. count = srcs. length;
// Traverse the image to be loaded
For (I = 0, length = srcs. length; I <length; I ++ ){
// Create a node
Node = this. createNode (srcs [I], options, notice, group );
// Determine whether the thread pool is idle
Free = this. getFree ();
If (free ){
// If the image is idle, load the image immediately.
This. setSrc (free. img, node );
} Else {
// Add the task to the linked list if it is not idle
This. appendNode (node );
}
}
};
/**
* Obtain internal status information
* @ Returns {{}}
*/
ImagePool.prototype.info = function (){
Var info = {},
Length = 0,
I = 0,
Node = null;
// Thread
Info. thread = {};
// Total number of threads
Info. thread. count = this. pool. length;
// Number of Idle threads
Info. thread. free = 0;
// Task
Info. task = {};
// Number of pending tasks
Info. task. count = 0;
// Obtain the number of idle "Threads"
For (I = 0, length = this. pool. length; I <length; I ++ ){
If (this. pool [I]. free ){
Info. thread. free = info. thread. free + 1;
}
}
// Obtain the number of tasks (Task chain length)
Node = this. linkHead;
If (node ){
Info. task. count = info. task. count + 1;
While (node. next ){
Info. task. count = info. task. count + 1;
Node = node. next;
}
}
Return info;
};
/**
* Create a node
* @ Param src: Specifies the image path. String.
* @ Param options User-Defined parameters. Including success callback, error callback, And once identity.
* @ Param notice: callback policy. Function.
* @ Param group information. Object. {Count: 0, success: [], error: []}
* @ Param tr error retries. Value. The default value is 0.
* @ Returns {{}}
*/
ImagePool. prototype. createNode = function (src, options, notice, group, tr ){
Var node = {};
Node. src = src;
Node. options = options;
Node. notice = notice;
Node. group = group;
Node. try = tr | 0;
Return node;
};
/**
* Append a node to the end of the task linked list
* @ Param node. Object.
*/
ImagePool. prototype. appendNode = function (node ){
// Judge whether the linked list is empty
If (! This. linkHead ){
This. linkHead = node;
This. linkNode = node;
} Else {
This. linkNode. next = node;
This. linkNode = node;
}
};
/**
* Delete the linked list Header
*/
ImagePool. prototype. shiftNode = function (){
// Determine whether the linked list has nodes
If (this. linkHead ){
// Modify the linked list Header
This. linkHead = this. linkHead. next | null;
}
};
/**
* Export external interface
* @ Param max the maximum number of connections. Value.
* @ Returns {load: Function, info: Function }}
*/
Exports. initImagePool = function (max ){
If (! Instance ){
Instance = new ImagePool (max );
Instance. initPool ();
}
Return {
/**
* Loading Images
*/
Load: function (){
Instance. load. apply (instance, arguments );
},
/**
* Internal information
* @ Returns {* | any | void}
*/
Info: function (){
Return instance.info. call (instance );
}
};
};
} (This ));
The above is an example of how to use this amazing javascript front-end image loading manager. Have you learned how to use it?