jQuery 延迟 AJAX 调用 return 值

jQuery deferred AJAX call return value

我有一个函数,它将 return 一个缓存的模板,或者如果模板没有被缓存 - 它会通过 AJAX 加载它,然后 return 它。这是我得到的:

var getTpl = function( name ) {

    var cached = cache.get( 'templates' ) || {};

    if( cached.hasOwnProperty( name ) ) {

        console.log( 'template ' + name + '.mustache found in cache' );

        return cached[ name ];

    }

    else {

        console.log( 'requesting ' + name + '.mustache template via AJAX' );

        var tpl;

        $.ajax( {

            url: path.templates + '/' + name + '.mustache',
            async: false,
            success: function( data ) {

                tpl = data;

                var cached      = store.get( 'miniTemplates' ) || {};
                var newTemplate = {};

                newTemplate[ name ] = data;

                if( ! cached.hasOwnProperty( name ) ) cache.set( 'templates', _.extend( cached, newTemplate ) )

            },
            error: function() { tpl = false; }

        } );

        return tpl;

    }

}

这很好用。但是,Chrome 抱怨:

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.

因此我想改用 $.deferred,但我无法理解它。我怎样才能重写上面的函数,所以调用 getTpl 总是 return 一个模板(形成缓存或直接来自 AJAX 请求)?

您可以使用promise/deferred概念来实现您的需求

var getTpl = function( name ) {
   var promise;

    var cached = cache.get( 'templates' ) || {};

    if( cached.hasOwnProperty( name ) ) {

        console.log( 'template ' + name + '.mustache found in cache' );

        var df = new $.Deferred();
        df.resolve(cached[ name ]);

        promise = df.promise();

    } else {
        console.log( 'requesting ' + name + '.mustache template via AJAX' );

        promise = $.ajax({
            url: path.templates + '/' + name + '.mustache'
        }).then(function(data) {
            tpl = data;

            var cached      = store.get( 'miniTemplates' ) || {};
            var newTemplate = {};

            newTemplate[ name ] = data;

            if( ! cached.hasOwnProperty( name ) ) cache.set( 'templates', _.extend( cached, newTemplate ) )

            return tpl;
        });

    }

    return promise;

}

然后,像这样调用你的方法:

getTpl('xyz')
    .then(function(template) {
        // you have the template, either from cache or fetched via ajax
    })
    .fail(function(err) {
        console.log(err);
    });

由于您似乎已经在使用 underscore/lodash,您可以使用记忆而不是维护自己的缓存。

promise 的美妙之处在于您可以一次又一次地访问它们,并且它们将始终产生相同的值:

var getTpl = _.memoize(function( name ) {
    console.log( 'requesting ' + name + '.mustache template via AJAX' );

    return $.ajax({
        url: path.templates + '/' + name + '.mustache'
    });
});

是的,就是这么简单。

然后你就可以像使用任何其他 promise 一样使用它了:

getTpl('myTemplate').then(function (template) {
    // use template
}, function (error) {
    console.log('Could not retrieve template.', error);
});