首頁 > web前端 > js教程 > JavaScript前端圖片載入管理器imagepool使用詳解_基礎知識

JavaScript前端圖片載入管理器imagepool使用詳解_基礎知識

WBOY
發布: 2016-05-16 16:23:34
原創
1303 人瀏覽過

前言

      imagepool是管理圖片載入的JS工具,透過imagepool可以控制圖片並發載入個數。

      對於圖片加載,最原始的方式就是直接寫個img標籤,例如:JavaScript前端圖片載入管理器imagepool使用詳解_基礎知識

      經過不斷優化,出現了圖片延遲載入方案,這回圖片的URL不直接寫在src屬性中,而是寫在某個屬性中,例如:JavaScript前端圖片載入管理器imagepool使用詳解_基礎知識。這樣瀏覽器就不會自動載入圖片,等到一個恰當的時機需要載入了,則用js把data-src屬性中的url放到img標籤的src屬性中,或是讀出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",{
     success: function(src){
         console.log("success:::::" src);
     },
     error: function(src){
         console.log("error:::::" src);
     }
 });

     直接在實例上呼叫load方法即可。

     load法有兩個參數。第一個參數是需要載入的圖片url,第二個參數是各種選項,包含了成功、失敗的回調,回呼時會傳入圖片url。

     這樣寫只能傳入一張圖片,因此,也可以寫成以下形式:

複製程式碼 程式碼如下:

 var imagepool = initImagePool(10);
 imagepool.load(["圖片1url","圖片2url"],{
     success: function(src){
         console.log("success:::::" src);
     },
     error: function(src){
         console.log("error:::::" src);
     }
 });

     透過傳入一個圖片url數組,就可以傳入多個圖片了。

     每個圖片載入成功(或失敗),都會呼叫success(或error)方法,並且傳入對應的圖片url。

     但有時候我們並不需要這樣頻繁的回調,傳入一個圖片url數組,當這個數組中所有的圖片都處理完成後,再回調就可以了。

     只要增加一個選項:

複製程式碼 程式碼如下:

 var imagepool = initImagePool(10);
 imagepool.load(["圖片1url ","圖片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
 });

     在選項中加上一個once屬性,並設為true,即可實現只回調一次。

     這次回調,必然回調success方法,此時error方法是被忽略的。

     此時回調success方法,不再是傳入一個圖片url參數,而是傳入三個參數,分別為:成功的url數組、失敗的url數組、總共處理的圖片數量。

     另外,也有一個方法可以取得連接池內部狀態:

複製程式碼 程式碼如下:

 var imagepool = initImagePool(10);
 console.log(imagepool.info());

     可透過呼叫info方法,可得到當下時刻連接池內部狀態,資料結構如下:

     Object.task.count 連線池中等待處理的任務數量
     Object.thread.count 連線池最大連線數
     Object.thread.free 連線池閒置連線數
 
     建議不要頻繁地呼叫此方法。

     最後要說明的是,如果圖片載入失敗,最多會嘗試3次,如果最後還是載入失敗,才回呼error方法。嘗試次數可在原始碼中修改。

     最最後再強調一下,讀者可以盡情的往連接池中push圖片,完全不必擔心並發過多的問題,imagepool會有條不絮的幫你加載這些圖片。

     最最最後,必須說明的是,imagepool理論上不會降低圖片載入速度,只不過是平緩的載入。

源碼

複製程式碼 程式碼如下:

(function(exports){
    //單例
    var instance = null;
    var emptyFn = function(){};
    //初始預設設定
    var config_default = {
        //執行緒池"執行緒"數量
        thread: 5,
        //圖片載入失敗重試次數
        //再試2次,加上原有的一次,總共是3次
        "try": 2
    };
    //工具
    var _helpers = {
        //設定dom屬性
        setAttr: (function(){
            var img = new Image();
            //判斷瀏覽器是否支援HTML5 dataset
            if(img.dataset){
                return function(dom, name, value){
                    的.dataset[name] = value;
                    return value;
                };
            }else{
                return function(dom, name, value){
                    dom.setAttribute("data-" name, value);
                    return value;
                };
            }
        }()),
        //取得dom屬性
        getAttr: (function(){
            var img = new Image();
            //判斷瀏覽器是否支援HTML5 dataset
            if(img.dataset){
                return unction(dom, name){
                    return dom.dataset[name];
                };
            }else{
                return unction(dom, name){
                    return dom.getAttribute("data-" name);
                };
            }
        }())
    };
    /**
     * 構造方法
     * @param max 最大連線數。數值。
    */
    function ImagePool(max){
        //最大併發數量
        this.max = max || config_default.thread;
        this.linkHead = null;
        this.linkNode = null;
        //載入池
        //[{img: dom,free: true, node: node}]
        //node
        //{src: "", options: {success: "fn",error: "fn", once: true}, try: 0}
        this.pool = [];
    }
    /**
     * 初始化
    */
    ImagePool.prototype.initPool = function(){
        var i,img,obj,_s;
        _s = 這個;
        for(i = 0;i             obj = {};
            img = new Image();
            _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 node = _s.getNode(this);
                //判斷嘗試次數
                if(node.try                     節點.try = 節點.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 node 節點。對象。
     * @param status 狀態。字串。可選值:success(成功)|error(失敗)
     * @param src 圖片路徑。字串。
    */
    ImagePool.prototype.notice = function(node, status, src){
        node.notice(status, src);
    };
    /**
     * 處理鍊錶任務
     * @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,
            //只初始化一次回呼策略
            notice = (function(){
                if(options.once){
                    return src){
                        var g = this.group,
                            o = this.options;
                        //記錄
                        g[status].push(src);
                        //判斷重組是否完成已完成
                        if(g.success.length g.error.length === g.count){
                            //非同步上
                 地                             setTimeout(function(){
                                o.success.call(null, g.suess, g.error, gcount);                             },1);
                        }
                    };
                }else{
                    return src){
                        var o = this.options;
                        //直接回復
                        setTimeout(function(){
                            o[status].call(null, src);
                        },1);
                    };
                }
            }()),
            group = {
                count: 0,
                success: [],
                error: []
            },
            node = null;
        options = options || {};
        options.success = options.success || emptyFn;
オプション.エラー = オプション.エラー || 空の Fn;
srcs = srcs.concat(src);
//グループ要素の数を設定します
group.count = srcs.length;
// ロードする必要がある画像をスキャンします
for(i = 0, length = srcs.length; i //ノードを作成します
node = this.createNode(srcs[i], options, Notice, group);
//スレッドプールが空いているかどうかを判断します
無料 = this.getFree();
if(無料){
//時間があればすぐに画像を読み込みます
This.setSrc(free.img, ノード);
}その他{
//アイドル時間はないので、リンクされたリストにタスクを追加します
This.appendNode(ノード);
}
}
};
/**
* 内部ステータス情報を取得します
* @returns {{}}
​​*/
ImagePool.prototype.info = function(){
var info = {},
長さ = 0,
i = 0、
ノード = null;
//スレッド
info.thread = {};
//スレッドの総数
info.thread.count = this.pool.length;
//アイドル状態のスレッドの数
info.thread.free = 0;
//タスク
info.task = {};
//処理するタスクの数
info.task.count = 0;
//アイドル状態の「スレッド」の数を取得します
for(i = 0, length = this.pool.length; i If(this.pool[i].free){
info.thread.free = info.thread.free 1;
}
}
//タスク数(タスクチェーン長)を取得
ノード = this.linkHead;
if(ノード){
info.task.count = info.task.count 1;
while(node.next){
info.task.count = info.task.count 1;
ノード = ノード.ネクスト;
}
}
情報を返す;
};
/**
* ノードの作成
* @param ソース画像パス。弦。
* @param オプション ユーザー定義のパラメーター。含まれるもの: 成功コールバック、エラー コールバック、および 1 回の識別子。
* @param 通知コールバック戦略。 関数。
* @param group グループ情報。物体。 {カウント: 0、成功: []、エラー: []}
* @param tr エラーの再試行回数。数値。デフォルトは 0 です。
* @returns {{}}
*/
ImagePool.prototype.createNode = function(src, options, Notice, group, tr){
var ノード = {};
Node.src = src;
Node.options = オプション;
Node.notice = 通知;
Node.group = グループ;
ノード.try = tr ||
return ノード;
};
/**
* タスクリストの最後にノードを追加します
* @param ノードノード。物体。
​​*/
ImagePool.prototype.appendNode = function(node){
//リンクされたリストが空かどうかを判断します
if(!this.linkHead){
This.linkHead = ノード;
This.linkNode = ノード;
}その他{
This.linkNode.next = ノード;
This.linkNode = ノード;
}
};
/**
* リンクリストのヘッダーを削除
​​*/
ImagePool.prototype.shiftNode = function(){
//リンクリストにノードがあるかどうかを判断します
if(this.linkHead){
//リンクリストのヘッダーを変更します
This.linkHead = this.linkHead.next ||
}
};
/**
* 外部インターフェースをエクスポート
* @param max 接続の最大数。数値。
* @returns {{load: 関数、info: 関数}}
​​*/
exports.initImagePool = function(max){
if(!instance){
インスタンス = 新しい ImagePool(max);
インスタンス.initPool();
}
return {
/**
* 写真を読み込み中
                               */
load: function(){
Instance.load.apply(インスタンス, 引数);
},
/**
*内部情報
* @returns {*|any|void}
                               */
info: function(){
returninstance.info.call(instance);
}
};
};
}(これ));

上記は、この優れた JavaScript フロントエンド画像読み込みマネージャーの使用方法の例です。使い方を学びましたか?

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板