2

RequireJS ローダー プラグインを作成しています。このプラグインは、EasyXDM を介してドメインを越えて HTML フラグメントをフェッチします。次のように、ローダー構文を使用して呼び出されます。

'html!someTemplate,#fragmentSelector'

同じ HTML ドキュメントから異なるフラグメントをリクエストするなど、多くの繰り返しリクエストが発生する可能性があるため、HTML ドキュメント全体とフラグメントの両方をキャッシュしたいと考えています。しかし、RequireJS ローダー プラグインの理解に大きな穴があるように見えるため、今のところキャッシュを行うことはできません提供されたonLoad()関数を呼び出して完了を通知するまで、再度呼び出されることはないと思いました。しかし、そうではありません。コンソール ステートメントを使用してデバッグすると、 onLoad()を呼び出す前に、62 回の呼び出し (このアプリでは合計 62 個のアセット要求があります) が立て続けに行われることがわかりました。. 非同期部分にパススルーする前にこれらのキャッシュをチェックしようとしましたが、62 回すべての呼び出しが非同期部分にパススルーされたため、キャッシュには何もありません。これらの 62 回の非同期呼び出しは適切なデータを返すため、最終的にプラグインは正常に動作します。しかし、私のキャッシングはそうではなく、私の人生では、これを解決する方法を理解することはできません. どんな助けでも大歓迎です。

4

1 に答える 1

0

わかりました、ついにこれを行う方法を見つけました。口頭では、ローダーへのすべての呼び出しをキューに入れ、一度に 1 つずつ処理する必要があります。次のコード ポイントで、キューから 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"
    };

});
于 2013-05-02T05:07:08.227 に答える