JavaScript設(shè)計(jì)模式--代理模式

一、定義

代理模式:為一個(gè)對(duì)象提供一個(gè)代用品或占位符,以便控制對(duì)它的訪問。
代理分為:保護(hù)代理和虛擬代理
保護(hù)代理:用于控制不同權(quán)限的對(duì)象對(duì)目標(biāo)對(duì)象的訪問,在 JavaScript 中很難判斷誰訪問了某個(gè)對(duì)象,所以保護(hù)代理很難實(shí)現(xiàn)。

二、圖片預(yù)加載(最常見的虛擬代理應(yīng)用場(chǎng)景)

圖片預(yù)加載是一種常用技術(shù),如果直接給某個(gè) img 標(biāo)簽節(jié)點(diǎn)設(shè)置 src 屬性,由于圖片過大或者網(wǎng)絡(luò)不佳,圖片的位置往往有段時(shí)間會(huì)有空白。

常見的做法事先用一張 loading 圖片占位,然后異步加載圖片,待圖片加載完成,把其填充到 img 節(jié)點(diǎn)里。

實(shí)現(xiàn)原理:
創(chuàng)建一個(gè) Image 對(duì)象:var a = new Image();
定義 Image 對(duì)象的 src: a.src = “xxx.gif”;
這樣做就相當(dāng)于給瀏覽器緩存了一張圖片。

可通過 Image 對(duì)象的 complete 屬性來檢測(cè)圖像是否加載完成。每個(gè) Image 對(duì)象都有一個(gè) complete 屬性,當(dāng)圖像處于裝載過程中時(shí),該屬性值 false,當(dāng)發(fā)生了 onload、onerror、onabort 中任何一個(gè)事件后,則表示圖像裝載過程結(jié)束,此時(shí) complete 屬性為 true。

(1)非代理實(shí)現(xiàn)

var myImage = (function() {
    var imgNode = document.createElement("img");
    document.body.appendChild(imgNode);    var img = new Image();

    img.onload = function() {
        imgNode.src = img.src;
    };    return {
        setSrc: function(src) {
            imgNode.src = "./images/loading.gif";
            img.src = src;
        }
    }
})();

myImage.setSrc("./images/originImg.png");

(2)代理實(shí)現(xiàn)

// 創(chuàng)建圖片
DOMvar myImage = (function() {
    var imgNode = document.createElement("img");
    document.body.appendChild(imgNode);    return {
        setSrc: function(src) {
            imgNode.src = src;
        }
    };
})();// 代理
var proxyImage = (function() {
    var img = new Image();

    img.onload = function() {
        myImage.setSrc(this.src);
 // this指向img!img加載完成后,將img.src傳遞給myImage
    };    return {
        setSrc: function(src) {
            myImage.setSrc("./images/loading.gif");
 // loading
            img.src = src;
        }
    };
})();

proxyImage.setSrc("./images/originImg.png");

使用代理模式的好處:使每個(gè)函數(shù)功能單一,實(shí)現(xiàn)對(duì)象設(shè)計(jì)的“單一職責(zé)原則”!

三、文件同步

假設(shè)我們?cè)谧鲆粋€(gè)文件同步功能,當(dāng)選中 checkbox 時(shí)候,它對(duì)應(yīng)的文件就會(huì)被同步到另外一臺(tái)服務(wù)器。

<body>
        <input type="checkbox" id="1" />文件1
        <input type="checkbox" id="2" />文件2
        <input type="checkbox" id="3" />文件3
        <input type="checkbox" id="4" />文件4
        <input type="checkbox" id="5" />文件5
        <input type="checkbox" id="6" />文件6
    </body>

沒選中一個(gè) checkbox 就同步一次,顯然不太合理。因?yàn)樵?web 開發(fā)中,最大的開銷就是網(wǎng)絡(luò)請(qǐng)求。
解決方案方案:通過一個(gè)代理函數(shù)來收集一段時(shí)間之內(nèi)的請(qǐng)求,然后一次性發(fā)給服務(wù)器。

var synchronousFile = function(id) {
    console.log("開始同步文件,id為:" + id);
};var proxySynchonousFile = (function() {
    var cache = [],     // 保存本次需要同步文件的id
        timer;          // 定時(shí)器

    return function(id) {
        cache.push(id);        if(timer) {
            // 不要覆蓋已經(jīng)啟動(dòng)的定時(shí)
            return;
        }

        timer = setTimeout(function(){
            synchronousFile(cache.join(","));
            clearTimeout(timer);
            timer = null;
            cache.length = 0;   // 清空緩存
        }, 2000);
    }
})();
var checkboxs = document.getElementsByTagName("input");
for(var i = 0, c;
c = checkboxs[i]; i++) {
    c.onclick = function() {
        if(this.checked === true) {
            proxySynchonousFile(this.id);
        }
    }
}

四、緩存代理–計(jì)算乘積(序列一模一樣)

var mult = function() {
    var result = 1;
for(var i = 0, l = arguments.length; i < l; i++) {
        result= result * arguments[i];
    }    return result;
};var proxyMult = (function() {
    var cache = {};
// {"1,2,3": 6}
    return function() {
        var args = Array.prototype.join.call(arguments, ",");
if(args in cache) {            return cache[args];
        }        return cache[args] = mult.apply(this, arguments);
    }
})();

console.log(proxyMult(1, 2, 3));
// 改造:
var proxyFactory = function(fn) {
    var cache = {};    return function() {
        var args = Array.prototype.join.call(arguments, ",");
 if(args in cache) {            return cache[args];
        }        return cache[args] = fn.apply(this, arguments);
    }
};

console.log(proxyFactory(mult)(1, 2, 3));
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容