はしがき
Imagepool は、同時にロードされるイメージの数を制御できる、イメージのロードを管理するための JS ツールです。
画像をロードする場合、最も原始的な方法は、 のような img タグを直接記述することです。
継続的な最適化の後、画像の遅延読み込みソリューションが登場しました。今回は、画像の URL が src 属性に直接記述されるのではなく、。このように、適切なタイミングで画像をロードする必要がある場合は、js を使用して、img タグの src 属性に URL を入れるか、URL を読み取った後にブラウザが画像を自動的にロードしません。 , jsを使って画像を読み込み、読み込み完了後にsrc属性を設定して画像を表示します。
これはうまく制御されているようですが、まだ問題があります。
画像の一部のみをロードすることは可能ですが、画像のこの部分は依然として比較的大きな桁数である可能性があります。
これは PC 側では大した問題ではありませんが、モバイル側では大量の画像が同時に読み込まれるため、アプリケーションがクラッシュする可能性が非常に高くなります。
したがって、画像読み込みの同時実行を制御するための画像バッファリング メカニズムが緊急に必要です。バックエンド データベース接続プールと同様に、あまりにも多くの接続が作成されることはなく、各接続を完全に再利用できます。
この時点で、imagepool が誕生しました。
回路図が不十分
使用説明書
まず、接続プールを初期化する必要があります:
var imagepool = initImagePool(5);
initImagePool はグローバル メソッドであり、どこでも直接使用できます。この機能は接続プールを作成することであり、接続プール内の最大接続数をオプションで指定できます。デフォルトは 5 です。
同じページで initImagePool を複数回呼び出すと、同じコア インスタンス (常に最初のインスタンス) が返され、シングルトンのように感じられます。例:
var imagepool1 = initImagePool(3);
var imagepool2 = initImagePool(7);
現時点では、imagepool1 と imagepool2 の最大接続数は 3 であり、内部的には同じコア インスタンスが使用されます。内部コアは同じであり、imagepool1 === imagepool2 ではないことに注意してください。
初期化後は、安心して画像を読み込むことができます。
最も単純な呼び出し方法は次のとおりです:
var imagepool = initImagePool(10);
imagepool.load("画像 URL",{
成功: function(src){
console.log("success:::::" src);
}、
エラー: function(src){
console.log("error:::::" src);
}
});
インスタンス上で直接、load メソッドを呼び出すだけです。
ロードメソッドには 2 つのパラメータがあります。最初のパラメータはロードする必要がある画像の URL で、2 番目のパラメータは成功および失敗のコールバックを含むさまざまなオプションです。画像の URL はコールバック中に渡されます。
この方法では 1 つの画像のみを渡すことができるため、次の形式で記述することもできます:
var imagepool = initImagePool(10);
imagepool.load(["image1url","image2url"],{
成功: function(src){
console.log("success:::::" src);
}、
エラー: function(src){
console.log("error:::::" src);
}
});
画像 URL 配列を渡すことで、複数の画像を渡すことができます。
画像が正常にロードされる (または失敗する) たびに、success (または error) メソッドが呼び出され、対応する画像 URL が渡されます。
ただし、そのような頻繁なコールバックが必要ない場合もあります。画像 URL の配列を渡し、この配列内のすべての画像が処理された後にコールバックするだけです。
オプションを追加するだけです:
var imagepool = initImagePool(10);
imagepool.load(["image1url ","image2url "],{
成功: function(sArray, eArray, count){
console.log("sArray:::::" sArray);
console.log("eArray:::::" eArray);
console.log("カウント::::" カウント);
}、
エラー: function(src){
console.log("error:::::" src);
}、
1 回: true
});
オプションに Once 属性を追加して true に設定すると、コールバックを 1 つだけ実現できます。
このコールバックは必然的に success メソッドをコールバックします。このとき、error メソッドは無視されます。
このとき、success メソッドをコールバックする際、画像の URL パラメータを渡す代わりに、成功した URL 配列、失敗した URL 配列、処理された画像の総数の 3 つのパラメータが渡されます。
さらに、接続プールの内部ステータスを取得するメソッドがあります:
var imagepool = initImagePool(10);
console.log(imagepool.info());
info メソッドを呼び出すと、現時点での接続プールの内部状態を取得できます。データ構造は次のとおりです。
Object.task.count 接続プール内で処理を待機しているタスクの数
Object.thread.count 接続プール内の最大接続数
Object.thread.free 接続プール内のアイドル状態の接続の数
このメソッドを頻繁に呼び出さないことをお勧めします。
最後に注意すべき点は、画像の読み込みが失敗した場合、最大 3 回試行され、最終的に読み込みが失敗すると、エラー メソッドが呼び戻されるということです。試行回数はソースコードで変更できます。
最後に、読者は過剰な同時実行性を気にせずに、必要なだけイメージを接続プールにプッシュできることを強調したいと思います。Imagepool は、これらのイメージを順序立ててロードするのに役立ちます。
最後になりましたが、imagepool は理論的には画像の読み込み速度を低下させず、穏やかに読み込みを行うだけであることに注意する必要があります。
ソースコード
コードをコピー コードは次のとおりです:
(関数(エクスポート){
//単一のケース
var インスタンス = null;
var emptyFn = function(){};
//初期デフォルト設定
var config_default = {
//スレッドプール「スレッド」の数
スレッド: 5、
//画像読み込み失敗時のリトライ回数
// 2 回再試行し、元の再試行を加えて合計 3 回再試行します
「試してみる」: 2
};
//ツール
var _helpers = {
// dom 属性を設定します
setAttr: (function(){
var img = new Image();
//ブラウザが HTML5 データセットをサポートしているかどうかを判断します
if(img.dataset){
return 関数(dom, name, value){
dom.dataset[名前] = 値;
戻り値;
};
}その他{
return 関数(dom, name, value){
dom.setAttribute("data-" 名前, 値);
戻り値;
};
}
}())、
// dom 属性を取得します
getAttr: (function(){
var img = new Image();
//ブラウザが HTML5 データセットをサポートしているかどうかを判断します
if(img.dataset){
return function(dom, name){
dom.dataset[name];
を返します
};
}その他{
return function(dom, name){
return dom.getAttribute("data-" name);
};
}
}())
};
/**
※施工方法
* @param max 接続の最大数。数値。
*/
関数 ImagePool(max){
//同時実行の最大数
This.max = max || config_default.thread;
This.linkHead = null;
This.linkNode = null;
//プールを読み込み中
//[{img: dom,free: true, ノード: ノード}]
//ノード
//{src: ""、オプション: {success: "fn"、error: "fn"、1 回: true}、try: 0}
This.pool = [];
}
/**
* 初期化
*/
ImagePool.prototype.initPool = function(){
var i,img,obj,_s;
_s = これ;
for(i = 0;i
obj = {};
img = 新しい画像();
_helpers.setAttr(img, "id", i);
img.onload = function(){
var id,src;
//回调
//_s.getNode(this).options.success.call(null, this.src);
_s.notice(_s.getNode(this), "成功", this.src);
//处理任务
_s.executeLink(this);
};
img.onerror = function(e){
var ノード = _s.getNode(this);
// 判断尝试次数
if(node.try < config_default.try){
ノード.トライ = ノード.トライ 1;
// 次回任务链表末尾に追加
_s.appendNode(_s.createNode(node.src、node.options、node.notice、node.group、node.try));
}その他{
//エラー回调
//node.options.error.call(null, this.src);
_s.notice(node, "error", this.src);
}
//处理任务
_s.executeLink(this);
};
obj.img = img;
obj.free = true;
this.pool.push(obj);
}
};
/**
* コールバックのカプセル化
* @param ノードノード。物体。
* @param ステータスステータス。弦。オプションの値: success(成功)|error(失敗)
* @param ソース画像パス。弦。
*/
ImagePool.prototype.notice = function(node, status, src){
node.notice(ステータス, ソース);
};
/**
* * リンクされたリストのタスクを処理しています
* @param dom イメージ dom オブジェクト。物体。
*/
ImagePool.prototype.executeLink = function(dom){
// 链表に点が存在するかどうかを判断します
if(this.linkHead){
//追加下一图片
this.setSrc(dom, this.linkHead);
//연결리스트 헤더 제거
This.shiftNode();
}그 외{
// 자신의 상태를 유휴 상태로 설정
This.status(dom, true);
}
};
/**
* 유휴 "스레드" 가져오기
*/
ImagePool.prototype.getFree = function(){
변수 길이,i;
for(i = 0, 길이 = this.pool.length; i
If(this.pool[i].free){
return this.pool[i];
}
}
null을 반환합니다.
};
/**
* src 속성 설정 캡슐화
* src 속성을 변경하는 것은 이미지를 로드하는 것과 동일하므로 작업이 캡슐화됩니다
* @param dom 이미지 dom 객체. 물체.
* @param 노드 노드. 물체.
*/
ImagePool.prototype.setSrc = 함수(dom, 노드){
//풀의 "스레드"를 유휴 상태가 아닌 상태로 설정
This.status(dom, false);
//연관 노드
This.setNode(dom, node);
//이미지 로드
dom.src = node.src;
};
/**
* 풀의 "스레드" 상태 업데이트
* @param dom 이미지 dom 객체. 물체.
* @param 상태 상태. 부울. 선택 값: true(유휴) | false(유휴 아님)
*/
ImagePool.prototype.status = 함수(dom, 상태){
var id = _helpers.getAttr(dom, "id");
This.pool[id].free = 상태;
//유휴 상태, 관련 노드 지우기
if(상태){
This.pool[id].node = null;
}
};
/**
* 풀에 있는 "스레드"의 관련 노드를 업데이트하세요
* @param dom 이미지 dom 객체. 물체.
* @param 노드 노드. 물체.
*/
ImagePool.prototype.setNode = 함수(dom, 노드){
var id = _helpers.getAttr(dom, "id");
This.pool[id].node = 노드;
return this.pool[id].node === node;
};
/**
* 풀에서 "스레드"의 관련 노드를 가져옵니다
* @param dom 이미지 dom 객체. 물체.
*/
ImagePool.prototype.getNode = 함수(dom){
var id = _helpers.getAttr(dom, "id");
return this.pool[id].node;
};
/**
* 외부 인터페이스, 사진 로딩
* @param src는 src 문자열이거나 src 문자열의 배열일 수 있습니다.
* @param 옵션 사용자 정의 매개변수. 포함: 성공 콜백, 오류 콜백, 일회 식별자.
*/
ImagePool.prototype.load = 함수(src, 옵션){
var srcs = [],
무료 = null,
길이 = 0,
i = 0,
// コールバック戦略を 1 回のみ初期化します
注意 = (function(){
If(options.once){
戻り関数(ステータス, ソース){
var g = this.group,
o = this.options;
//記録
g[ステータス].push(src);
//再編成が完了したかどうかを判断します
If(g.success.length g.error.length === g.count){
//実際には、コールバック関数に時間がかかりすぎて画像の読み込み速度に影響を与えるのを防ぐために、別のタスクとして別個に実行されます
setTimeout(function(){
o.success.call(null, g.success, g.error, g.count);
},1);
}
};
}else{
戻り関数(ステータス, ソース){
var o = this.options;
//ダイレクトコールバック
setTimeout(function(){
o[ステータス].call(null, src);
},1);
};
}
}())、
グループ = {
カウント: 0、
成功: []、
エラー: []
},
ノード = null;
オプション = オプション {};
オプション.成功 = オプション.成功 || 空の Fn;
options.error = options.error || emptyFn;
srcs = srcs.concat(src);
//Set the number of group elements
group.count = srcs.length;
//Traverse the images that need to be loaded
for(i = 0, length = srcs.length; i < length; i ){
//Create node
node = this.createNode(srcs[i], options, notice, group);
//Determine whether the thread pool is free
free = this.getFree();
if(free){
//Load the image immediately if there is time
This.setSrc(free.img, node);
}else{
//There is no idle time, add the task to the linked list
This.appendNode(node);
}
}
};
/**
* Get 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 tasks to be processed
info.task.count = 0;
//Get 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;
}
}
//Get 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 node
* @param src image path. String.
* @param options User-defined parameters. Contains: success callback, error callback, and once identifier.
* @param notice callback strategy. function.
* @param group group information. object. {count: 0, success: [], error: []}
* @param tr Number of error retries. numerical value. Default 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 nodes to the end of the task list
* @param node node. object.
*/
ImagePool.prototype.appendNode = function(node){
//Determine 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 there is a node in the linked list
if(this.linkHead){
//Modify the linked list header
This.linkHead = this.linkHead.next || null;
}
};
/**
* Export external interface
* @param max The maximum number of connections. numerical value.
* @returns {{load: Function, info: Function}}
*/
exports.initImagePool = function(max){
if(!instance){
instance = new ImagePool(max);
instance.initPool();
}
return {
/**
* Loading pictures
*/
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 great JavaScript front-end image loading manager. Have you guys learned how to use it?