异步模板加载 - 如何只加载一次?

时间:2012-04-27 22:34:22

标签: javascript ajax templates

我有一个客户端JS应用程序需要加载模板来显示每个项目。让我们说他们是笔记。

问题出在异步部分。我无法使模板只加载一次。它会在每次注释调用render函数时加载。

以下是一些代码:

var notes = [ {}, {}, {} ] // Some Note objects
notes.forEach( function( note ) {
    render( note )
}

// Have some variable to hold the template
var template

// Now on the render function
function render( note ) {

    // First, if the template exists, go straight to the next function
    if ( template ) {

        // The display function takes care of appending the note
        // to the body after applying datas on the template
        display( note )
    }
    else {
        // loadTemplate just loads the template in an ajax request
        // and executes the callback with the template as argument
        loadTemplate( function( data ) {

            // I fill in the template variable
            template = data

            // And I display the note since the template is available
            display( note )
        } )
    }
}

所以在这种情况下它会加载模板的三倍,即使有一个检查来防止这种情况。我想这是因为这三个模板直接进入了else,但我怎么能阻止这个呢?

我不想使用同步ajax加载,因为这会冻结浏览器。

编辑:最后,我使用了@Managu的解决方案,略有修改。

我没有使用他的循环,而是使用了以下内容,更加优雅:

while ( backlog.length ) {
    display( backlog.shift() )
}

3 个答案:

答案 0 :(得分:2)

var loadTemplate = function() {
    var promise = $.get( "/" );

    loadTemplate = function() {
        return promise;
    };

    return promise;
};

请注意,这里不需要jQuery,我只是写为伪代码。您可以使用任何提供延迟的库。

loadTemplate().then( function( data ) {

    // I fill in the template variable
    template = data

    // And I display the note since the template is available
    display( note )
} )

答案 1 :(得分:1)

也许在加载模板后需要保留积压工作?基本上是一个队列,以平滑由异步引起的阻抗不匹配。

var template;
var backlog;

function render(note)
{
    if (template) {
        // Template already loaded, just display.
        display(note);
    } else if (backlog) {
        // Template being loaded, push work onto backlog.
        backlog.push(note);
    } else {
        // Template not being loaded yet.  Create backlog queue and launch request
        // to load template.
        backlog=[note];
        loadTemplate(function(loaded_template) {
            // Template finally came over the wire.  Save it, and then
            // work off the backlog.
            template = loaded_template;
            for (var note=backlog.shift(); 
                 backlog.length!=0;
                 note=backlog.shift())
            {
                display(note); 
            }
        } );
    }
}

答案 2 :(得分:0)

“我不想使用同步ajax加载,因为这会冻结浏览器。”

同步ajax只会在您尝试使用jQuery执行此操作时冻结浏览器。 Frame.js旨在解决与您一样的问题。使用Frame有多种方法可以解决此问题,但它们都涉及一定量的同步和异步混合。可能最简单的方法是:

Frame(function(next){
    loadTemplate(next);
});
Frame(function(next, data){ // data here is the value passed to loadTemplate's callback
    notes.forEach( function( note ) {
        template = data;
        display( note );
    });
    next();
});

如果您不确定模板是什么,并且每个音符可能相同或不同,那么您可以改为:

notes.forEach( function( note ) {
    Frame(function(next){
        loadTemplate(note.templateName, next); // next here is a callback to advance to the next Frame
    });
    Frame(function(next, template){
        display( note, template );
        next();
    });
});

这会加载模板同步,但显示更新异步。