2013-05-01 136 views
2

我正在寫一個RequireJS加載器插件。該插件通過EasyXDM跨域獲取html片段。它使用裝載機的語法調用,像這樣:如何使用緩存寫RequireJS loader插件?

'html!someTemplate,#fragmentSelector' 

由於可能會出現很多重複請求,例如請求從同一個HTML文檔不同的片段,我要同時緩存整個HTML文檔和片段。但我目前無法執行任何緩存,因爲我對RequireJS加載器插件的理解顯然有一個漏洞。我認爲它不會再被調用,直到它通過調用提供的onLoad()函數表示完成爲止。但這種情況並非如此。使用控制檯語句進行調試顯示,在我打電話給onLoad()之前,62個調用(在此應用程序中共有62項資產請求,總計)正在快速連續進行。我試圖在傳遞到異步部分之前檢查這些緩存,但是高速緩存中沒有任何內容,因爲所有62個調用都已傳遞到異步部分。這62個異步調用確實會返回良好的數據,因此最終該插件可以正常工作。但是我的緩存沒有,我不能爲我的生活決定如何解決這個問題。任何幫助將不勝感激。

回答

0

好吧,終於想出瞭如何做到這一點。在語言上,你必須做的是將所有調用加載到加載器,然後逐個處理它們。下面的代碼點,從隊列過程中它拉一個電話:

  • 異步調用後的第一次調用插件
  • 後完成每次
  • 您避免異步調用返回一個緩存值。

這裏的人誰可能需要一個例子

/** 
* RequireJS plugin for loading templates cross domain via easyXDM 
* Author: Larry Gerndt 
* Version: 0.0.1 (2013/5/1) 
* Usage: html!url,fragment-selector 
*  url: omit the .html extension 
*  fragment-selector: css selector of the fragment to extract 
*/ 
define(['assetLoader','jquery'], function(AssetLoader, $) { 
    /** 
    * Caches documents and fragments of documents 
    * The hash is derived from everything following the bang (!) 
    * For example, given this: html!assets/templates/IntroductionTooltip/introduction-tooltip,#mint-itt, we just 
    * strip out all illegal characters using the _hash() function and that's our hash for fragments. But we also 
    * want to cache the document from which the fragment came, in case a request is made for a different fragment from 
    * the same document. The hash for the document cache is made the same way as for fragments, except first omitting 
    * everything from the comma to the end of the line. In other words, omitting the fragment selector. 
    */ 
    function Cache(name) { 
     this.name = name; 
     this.cache = {}; 
     this.size = 0; 
    } 
    Cache.prototype = { 
     get: function(name) { 
      return this.cache[name]; 
     }, 
     has: function(name) { 
      return this.cache.hasOwnProperty(name); 
     }, 
     add: function(name, html) { 
      this.cache[name] = html; 
      this.size += 1; 
     } 
    }; 


    //----------------------------------------------------------------------------------------------------------- 
    // a FIFO queue that stores calls to this module 
    //----------------------------------------------------------------------------------------------------------- 

    function CallQueue() { 
     this.store = []; 
    } 
    CallQueue.prototype = { 
     push: function(name, req, onLoad, config) { 
      this.store.push({ 
       name : name, 
       req : req, 
       onLoad: onLoad, 
       config: config 
      }); 
     }, 
     pop: function() { 
      return this.store.length ? this.store.splice(this.store.length - 1, 1)[0] : null; 
     }, 
     isEmpty: function() { 
      return this.store.length === 0; 
     } 
    }; 

    var documentCache = new Cache('document'), 
     fragmentCache = new Cache('fragment'), 
     callQueue = new CallQueue(), 
     processedFirstCall = false; 

    //----------------------------------------------------------------------------------------------------------- 
    // helpers 
    //----------------------------------------------------------------------------------------------------------- 

    function getFragment(html, fragmentSelector) { 
     var $container, fragmentHtml; 
     if (!document.getElementById('mint-html-container')) { 
      $('body').append('<div id="mint-html-container" style="display:none;"></div>'); 
     } 
     $('#mint-html-container').html(html); 
     fragmentHtml = $(fragmentSelector).get(0).outerHTML; 
     return fragmentHtml; 
    } 

    function hash(string) { 
     return string.replace(/[\/,#\.\s\-]/g, ''); 
    } 

    function loadRemoteAsset(url, fragmentSelector, onLoad) { 
     var documentHash = hash(url), 
      fragmentHash = hash(url+fragmentSelector); 

     AssetLoader.loadHtmlFragment(url + '.html', fragmentSelector).then(function(fragmentHtml, allHtml) { 
      documentCache.add(documentHash, allHtml); 
      fragmentCache.add(fragmentHash, fragmentHtml); 
      onLoad(fragmentHtml); 
      processOneCall(); 
     }, function() { 
      onLoad.error('AssetLoader: failed for unknown reason'); 
     }); 
    } 

    function processOneCall() { 

     if (!callQueue.isEmpty()) { 
      var item = callQueue.pop(), 
       split = item.name.split(','), 
       url = split[0], 
       fragmentSelector = split[1]; 

      if (url.indexOf('/') === 0) { 
       url = item.config.baseUrl + url; 
      } 
      if (!url || !fragmentSelector) { 
       item.onLoad.error('AssetLoader: invalid argument: ' + item.name + '\n Example Usage: html!assets/templates/IntroductionTooltip/introduction-tooltip,#mint-itt'); 
      } 
      else { 
       var documentHash = hash(url), 
        fragmentHash = hash(url+fragmentSelector); 

       if (fragmentCache.has(fragmentHash)) { 
        item.onLoad(fragmentCache.get(fragmentHash)); 
        //console.log('using cached fragment for url: ', url, ', fragment: ', fragmentSelector); 
        processOneCall(); 
       } 
       else if (documentCache.has(documentHash)) { 
        var fragmentHtml = getFragment(documentCache.get(documentHash), fragmentSelector); 
        fragmentCache.add(fragmentHash, fragmentHtml); 
        item.onLoad(fragmentHtml); 
        //console.log('using cached document for url: ',url, ', fragment: ', fragmentSelector); 
        processOneCall(); 
       } 
       else { 
        loadRemoteAsset(url, fragmentSelector, item.onLoad); 
       } 
      } 
     } 
    } 

    //----------------------------------------------------------------------------------------------------------- 
    // public API 
    //----------------------------------------------------------------------------------------------------------- 

    return { 
     load : function(name, req, onload, config){ 
      callQueue.push(name, req, onload, config); 
      if (!processedFirstCall) { 
       processedFirstCall = true; 
       processOneCall(); 
      } 
     }, 
     pluginBuilder: 'html-builder' // uses this no-op module during Optimizer build to avoid error "window is not defined" 
    }; 

}); 
代碼