【问题标题】:How to write RequireJS loader plugin with cache?如何编写带有缓存的 RequireJS 加载器插件?
【发布时间】:2013-04-25 05:03:21
【问题描述】:

我正在编写一个 RequireJS 加载器插件。该插件通过 EasyXDM 跨域获取 html 片段。它使用加载器语法调用,如下所示:

'html!someTemplate,#fragmentSelector'

由于可能会出现许多重复请求,例如从同一个 HTML 文档请求不同的片段,我想缓存整个 HTML 文档和片段。但到目前为止,我还不能进行 任何 缓存,因为我对 RequireJS 加载器插件的理解显然存在很大的漏洞。我认为它不会被再次调用,直到它通过调用提供的 onLoad() 函数发出完成信号。但这种情况并非如此。使用控制台语句进行调试显示,在我调用 onLoad() 之前,快速连续进行了 62 次调用(在此应用中总共有 62 个资产请求)。我尝试在传递到异步部分之前检查这些缓存,但缓存中从来没有任何内容,因为所有 62 个调用都已传递到异步部分。这 62 个异步调用确实返回了良好的数据,所以最终插件工作正常。但是我的缓存没有,而且我一生都无法弄清楚如何解决这个问题。任何帮助将不胜感激。

【问题讨论】:

    标签: plugins asynchronous requirejs loader


    【解决方案1】:

    好的,终于知道如何做到这一点了。口头上,您要做的是将所有对加载程序的调用排队,然后一次处理一个。在以下代码点,从队列中拉出一个调用来处理它:

    • 第一次调用插件后
    • 异步调用完成后
    • 每次您通过返回缓存值来避免异步调用。

    这里是任何可能需要示例的人的代码

    /**
     * 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"
        };
    
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 2015-04-21
      • 1970-01-01
      • 2021-08-05
      • 2015-02-01
      相关资源
      最近更新 更多