聽說,代理模式真的只是個搞代購的?

chenhongdong發表於2019-02-28

存在即合理

總有些東西是值得研究研究的,雖然我對設計模式也不是很懂,但是學習研究了一下還是覺得受益匪淺的。

我們學習每一個知識點的時候都希望能一下子就能領悟,能吸收成為自己所用的技能。當然這也因人而異了

所以無論怎樣,在學習研究的道路上,我們都沒有放棄過,不拋棄不放棄應該是前端er給自己的一個口號了,加油,不再囉嗦了,直接進入今天的主題吧

代理模式

知其然當然要知其所以然

首先我們要知道什麼是代理模式?

  • 它是為一個物件提供一個代替品佔位符,以便控制對它的訪問

然後在生活當中更是無處不在的

  • 歌手的經紀人啊
  • 球星(C羅、梅西)的經紀人啊
  • 買化妝品的代購啊
  • 等等等等

其實容易理解的就是: 遇到什麼事,都交給那個有解決能力的人就對了

歌手接受採訪經紀人來安排,球星轉會俱樂部和經紀人來談,買國外的化妝品找代購來搞定

光說不練假把式,還是實際一點,一起來看看代理模式在開發中的一些應用吧!

實際應用中是這樣的

代理實現圖片預載入

大家都知道如果頁面載入圖片的話,圖片資源如果在網路情況較差的時候,載入是需要一些時間的,而且img元素在直接載入時也會出現一段時間的空白,這對體驗來說是不好的

所以我們就需要先用一個佔點陣圖(如loading圖),等真正的圖片資源請求完成後再替換掉

下面先來看看程式碼

let myImg = (function() {
    let img = document.createElement(`img`);
    document.body.appendChild(img);

    return {
        // 設定真正的圖片資源
        setSrc(src) {
            img.src = src;
        }
    }
})();

// 代理物件proxyImg
let proxyImg = (function() {
    let img = new Image();
    img.onload = function() {
        // 當圖片資源載入成功後
        // 再重新給img的src賦值
        myImg.setSrc(this.src);
    }

    return {
        setSrc(src) {
            // 先給img元素設定loading圖佔位
            myImg.setSrc(`https://p.ssl.qhimg.com/t0103b3b9a54ba2c6f5.gif`);
            img.src = src;
        }
    }
})();

proxyImg.setSrc(`http://p0.so.qhimgs1.com/bdr/326__/t015b81c99692979474.jpg`);
複製程式碼

OK,通過上面的程式碼就實現了一個圖片代理預載入的技術點。

當然了,有時候會發現,其實不用代理也完全可以實現啊,把img.onload的那些程式碼寫到myImg的程式碼塊中也是OK的啊,何必多此一舉,又造了一個代理函式呢?

  • 主要是代理函式它的作用是用來預載入處理的,如果以後網速快如閃電的話,那還需要預載入嗎?
  • 答案肯定是不需要了,那我們就還要回到myImg的程式碼中去找img.onload的操作,然後再根據無用的程式碼進行刪除(萬一刪錯了怎麼辦,會出事故的)
  • 但用到了代理函式就不需要這樣了,不再呼叫即可了,按照下面這樣寫就好了
    myImg.setSrc(`http://p0.so.qhimgs1.com/bdr/326__/t015b81c99692979474.jpg`);
    複製程式碼

合併http請求

在web開發中,最大的開銷莫過於就是網路請求了

例如在一些同步檔案上傳的情況下,如果是點選一個核取方塊就傳送一次請求的話,這樣多搞個幾次,伺服器的壓力就會變大了,身為前端不能這麼搞伺服器的,不夠仁義啊

那麼應該如何是好呢?不要方,按照代理模式的開發思路應該就是,不用自己親自上,交給代理來

實現的原理其實就是把點選到的要同步的檔案先存起來,然後在一個合理的延遲時間後再統一傳送這次的請求就好了(這一步放到代理中來做)

// 同步檔案函式
function syncFile(id) {
    const url = `xxx.com/index.php`;
    axios.get(url, {
        params: {
            id
        }
    });
}
let proxySyncFile = (function() {
    // cache儲存一段時間內需要同步的id
    let cache = [],     
        timer;

    return function(id) {
        cache.push(id);
        // 保證不會覆蓋之前的定時器
        if (timer) return;

        timer = setTimeout(function() {
            // 向2秒後本體傳送需要同步的id集合
            syncFile(cache.join(`,`));
            
            clearTimeout(timer);
            timer = null;
            cache.length = 0;  // 清空id集合
        }, 2000);
    }
})();
複製程式碼

以上程式碼就完成了代理合並http請求的實現了,下面再看一下使用就萬事大吉了

// 遍歷所有的checkbox元素
let checkbox = document.getElementsByTagName(`input`);

for (let i = 0; i < checkbox.length; i++) {
    let c = checkbox[i];
    // 給每一個checkbox元素新增click事件
    c.onclick = function() {
        // 被選中的情況下再觸發代理函式並傳入對應的id
        if (this.checked === true) {
            proxySyncFile(this.id);
        }
    };
}
複製程式碼

快取代理

快取代理可以為一些開銷大的運算結果提供暫時的儲存,在下次計算時

如果傳遞進來的引數和之前一致,則可以直接返回前面儲存的運算結果

下面以最常見的計算乘積的栗子來看一下吧

    // 計算乘積栗子
    function mult() {
        console.log(`開始計算乘積`);
        let a = 1;
        for (let i = 0, len = arguments.length; i < len; i++) {
            a = a * arguments[i];
        }
        return a;
    }
    // 快取代理
    let proxyMult = (function() {
        // 快取物件,用來儲存計算結果用的
        let cache = {};
        
        return function() {
            const args = Array.prototype.join.call(arguments, `,`);
            // 遍歷cache物件,看是否有上一次計算的引數
            if (args in cache) {
                console.log(`走了快取`);
                return cache[args];
            }
            return cache[args] = mult.apply(this, arguments);
        }
    })();
    
    console.log(proxyMult(2, 3));   // 開始計算乘積 6
    console.log(proxyMult(2, 3, 5, 10, 2)); // 開始計算乘積 600
    console.log(proxyMult(2, 3, 5, 10, 2)); // 走了快取 600
    console.log(proxyMult(2, 10, 2));   // 開始計算乘積 40
複製程式碼

利用快取來把開銷大的運算暫存起來確實是一種很有效的方法,下面我們再把這個快取代理做的更通用一些

不管是計算乘積還是計算加和我們都可以通過改造後的快取代理來實現,看程式碼

    function createProxy(fn) {
        let cache = {};
        return function() {
            const args = Array.prototype.join.call(arguments, `,`);
            if (args in cache) {
                return cache[args];
            }
            return cache[args] = fn.apply(this, arguments);
        }
    }
複製程式碼

以上程式碼唯一不同的地方就是把函式通過引數的形式傳進去就可以針對不同的計算函式來進行快取代理了,惟妙惟肖,確實是好方法,哈哈

總結

在開發中代理模式還是很重要的,值得我們多去寫寫,多去加以實踐

以上內容並不是很多,相比之前寫的篇幅大大縮減,但是初心不變,依然希望能給大家帶來一些好的內容分享出來,哈哈,感謝大家的觀看了!

相關文章