如何编写与缓存RequireJS加载插件? [英] How to write RequireJS loader plugin with cache?

查看:152
本文介绍了如何编写与缓存RequireJS加载插件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个RequireJS加载插件。该插件读取HTML片段通过EasyXDM跨域。它使用装载机的语法调用,就像这样:

I'm writing a RequireJS loader plugin. The plugin fetches html fragments cross domain via EasyXDM. It's invoked using the loader syntax, like this:

'html!someTemplate,#fragmentSelector'

由于可能会出现很多重复请求,例如请求来自同一个HTML文档不同片段,我想这两个缓存整个HTML文档和片段。但我不能做的任何的缓存,到目前为止,因为我显然有我RequireJS装载机插件的理解漏洞。我认为这将不会被再次调用,直到它通过调用提供的的onLoad()函数信号完成。但这种情况并非如此。调试与控制台报告显示,62电话(有62个资产的请求,总,在此应用程序),快速连续地由之前我曾经叫的onLoad()。我试图通过以异步部分之前检查这些缓存,但从来没有任何东西在缓存中,因为所有的62调用都通过对异步部分通过。那些62异步调用做回好数据,因此最终插件工作正常。但我的缓存不,我不能为我的生命弄清楚我们如何解决这个问题。任何帮助将大大AP preciated。

Since many repeat requests may occur, for example requesting different fragments from the same HTML document, I want to cache both the whole HTML document and the fragments. But I can't do any caching so far because I apparently have a gaping hole in my understanding of RequireJS loader plugins. I thought it would not get called again until it signaled completion by calling the supplied onLoad() function. But this is not the case. Debugging with console statements revealed that 62 calls (there are 62 asset requests, total, in this app) are made in rapid succession before I ever call onLoad(). I try to check the cache on these before passing through to the asynchronous part, but there is never anything in the cache because all 62 calls have passed through to the asynchronous part. Those 62 async calls do return good data, so ultimately, the plugin works fine. But my caching doesn't, and I can't for the life of me figure our how to solve this. Any help would be greatly appreciated.

推荐答案

好吧,终于想通了如何做到这一点。口头上,你必须做的就是排队装载机所有呼叫,然后处理它们一次。

Ok, finally figured out how to do this. Verbally, what you have to do is queue up all calls to the loader and then process them one at a time. At the following code points, pull one call from the queue process it:


  • 在第一次调用该插件后,

  • 异步调用完成后,

  • 每次返回一个缓存值避免异步调用的时间。

这里的code的人谁可能需要一个例子

Here's the code for anyone who might need an example

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

});

这篇关于如何编写与缓存RequireJS加载插件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆