qUIpt:一個很有創意的 JavaScript Cache Library

qUIpt 是一個很小很小的 JavaScript Library,所有原始碼也才只有 115 行而已(包括註解),我覺得作者 Mario Heiderich 真是太有創意了,他的原理十分簡單,使用的 Cache 方法是將資料儲存在 window 物件的 name 屬性中 ( window.name ),在這裡他是將透過 XHR ( XML Http Request ) 取回的 JavaScript 檔案內容儲存在 window.name 屬性裡。

通常 window.name 是用在 window.open() 的時候指定的第二的參數,還有當我們在表單(form)中設定 target 屬性的時候,這個 target 指定的就是 window.name 的值,但預設來說 window.name 大部分來講都是空的,所以 qUIpt 就拿這個屬性來做額外的快取(Cache)用途。

qUIpt 基本的運作流程如下:

  • 首先,他先檢查你的 window.name 是否有資料。
  • 如果 window.name 是空的,就透過 XHR 動態下載 JavaScript 檔案,並將檔案內容儲存在 window.name 屬性中。
  • 如果使用者第一次造訪你的網頁,或從其他網站進來的,就會先將 window.name 給清空,並重新下載 JS 檔回來。
  • 等使用者下次造訪你的網頁(例如連到下一頁),就直接用 eval() 函示將 window.name 的 JS 讀出執行,這樣所有物件都重新被載入回來了,完全不需要重新下載 JavaScript 檔。

底下這段 code 說明了這個運作流程:

/**
 * some security checks to avoid arbitrary off-site
 * self.name poisoning
 */

if(document.referrer == '' || 
   document.referrer.match(/\w+:\/\/[^\/]+/)[0] 
   !== location.href.match(/\w+:\/\/[^\/]+/)[0]) {
    self.name = '';
}

/**
 * let's start
 */
if(!self.name.length) {
    quipt_load();
} else {
    quipt_eval();
}

原理就是這麼簡單,你可以下載看原始碼回來看,才幾行而已,也許可以激發你一些更有創意的想法。

由於此專案十分的陽春,畢竟是第一版嘛,經我個人測試之後發現只有 Firefox 能用,IE 目前是無法執行的,所以我小修了一下程式把一些僅支援 Firefox 的語法給修正了,底下的 code 應該可以運作於 Firefox 與 IE 7 ( 其他版本的 IE 我沒測試過 )。

/**
 * quipt - caching in the name of performance
 *
 * @author  Mario Heiderich <mario.heiderich@gmail.com> , Will 保哥 <doggy.huang@gmail.com>
 * @license LGPL
 */
(function quipt_init() {

    /**
     * the config object
     */
    var quipt_config = {
        
        /**
         * the method to call when loading is done
         *
         * hint: just set it to false if not needed
         */
        'starter' : 'my_init_function', 
        
        /**
         * add files to load to this array
         * 
         * hint: you can add as many files as you wish - as long as they 
         *       come from the same domain. quipt also supports proxied 
         *       off-domain scripts.
         */
        'files'   : [
            'jquery-1.2.6.min.js',
            'dummy-js-file-01.js', 
            'dummy-js-file-02.js'
        ],
        
        /**
         * don't touch this - private stuff! else!
         */
        'status' : 0
    }
    
    var quipt_code = [];

    /**
     * the loader method - it monitors the status of the ressource 
     * fetching and kick-starts the XHR method
     * 
     */
    var quipt_load = function() {
        quipt_request();
    }   
    
    /**
     * this method just fires XHR requests against the files given in the 
     * config literal until all ressources are fetched
     * 
     */
    var quipt_request = function() {
            try {
                console.log('loading ressources from filesystem');
            } catch(e) {}
            
            var x = new XMLHttpRequest();
            x.open('GET', quipt_config.files[quipt_config.status], true);
            x.send(null);
            x.onreadystatechange = function() {
                if(x.readyState == 4 && x.status == 200) {
                    quipt_code.push(x.responseText);
                    quipt_config.status++;
                    self.name += x.responseText + ';\n';
                    if(quipt_config.status < quipt_config.files.length) {
                        quipt_request();
                    } else {
                        quipt_eval();
                    }
                }
            }
        }   
            
        /**
         * the eval method - which is called if window.name contains 
         * the right data
         */
        var quipt_eval = function() {
            self.eval(self.name);
            if(quipt_config.starter) {
                self[quipt_config.starter]();
            }
        }
        
        /**
         * some security checks to avoid arbitrary off-site
         * self.name poisoning
         */
        if(document.referrer == '' || document.referrer.match(/\w+:\/\/[^\/]+/)[0] 
            !== location.href.match(/\w+:\/\/[^\/]+/)[0]) {
            self.name = '';
        }
        
        /**
         * let's start
         */
        if(!self.name.length) {
            quipt_load();
        } else {
            quipt_eval();
        }
    })();

相關連結

  • qUIpt - Client side library caching with javaScript
  

此文章由 will 發表於 2008/7/9 上午 09:27:12

永久連結 | 評論 (7) | 此文章的RSSRSS comment feed |

分類: JavaScript | Web

標籤: ,

收藏:

相關文章

評論

七月 9. 2008 13:41

chainchung

請問, 一般的 javascript 不是都會被 IE cache 在 Temporary Internet Files 中? 這跟你上面提到的差別在那裏?

chainchung tw

七月 9. 2008 14:08

will

用 qUIpt 是完全 cache 在 Browser 的記憶體裡(window.name),完全不會寫入磁碟,所以快取的效能理論上來說是比較高的,也不需要依賴任何 Server 端程式的支援,例如說送出 HTTP 的 Cache 相關 Headers。

再者,這個技巧不止能快取 JavaScript 檔案而已,更重要的,你還可以寫入「短暫的跨網頁資料」喔!就像 Cookie 一樣,只是儲存在 window.name 裡面的資料完全不會透過 HTTP 傳輸,節省頻寬又存取快速,對於 Web 2.0 的網站來說是一個非常好用的解決方案,且「幾乎」沒有容量的上限,你想寫入多少就有多少!

例如說你登入會員後,需要顯示在頁面上的會員資料就可以暫存在 window.name 裡面。或是頁面上某些不會變動的區塊,可將 HTML 全部儲存在 window.name 裡面,每一頁要顯示的時候就從 window.name 抓取就好,整個網頁的 size 就可以大幅降低。

will tw

七月 9. 2008 16:08

chainchung

請問, 相對於原來的機制是由 client 端取得 js 檔來看, 這樣是否每次來這網頁都得重新由 server 端要一次 js 檔? 反而造成網路的使用量增加?

1. client 關閉頁面, 下次重開, 需從 server 再要一次
2. client 去其它站, 被清空, 下次進來得再跟 server 要一次

chainchung tw

七月 9. 2008 16:26

will

絕對不會!

因為 qUIpt 是用 XHR 下載檔案,只要下載的檔案(如:*.js)有送出 Cache Header 的話,瀏覽器一樣不會再到 server 要資料,不管怎麼樣,使用 qUIpt 時的檔案下載次數不會比不用 qUIpt 來的多(意思就是用 qUIpt 真的有 cache 到就是了啦)。

will tw

七月 16. 2008 16:36

Kaie

這的確是個很棒的idea,我試了IE7 的 window.name,似乎在reload之後window.name的值又被清空了... 好像只有第一次成功,後來被清掉,又沒有cache了

Kaie tw

七月 16. 2008 18:46

Will 保哥

我自己試 reload 是不會自動被清掉耶,除非你有寫程式自己去清他。

Will 保哥 tw

七月 16. 2008 18:53

Kaie

Sorry 我搞錯了,原來是在我的code中 document.referrer 值在IE是null,才會造成這個情況...誤會一場@@

Kaie tw

新增評論


(將顯示您的Gravatar圖示)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



線上預覽

二月 9. 2010 21:54