简体   繁体   中英

jQuery deferred AJAX call return value

I have a function, which will either return a cached template or if the template has not been cached - it will load it via AJAX and then return it. Here's what I've got:

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;

    }

}

This works fine. However, Chrome is complaining about:

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/.

Therefore I wanted to switch to using $.deferred , but I can't wrap my head around it. How can I re-write the function above, so calling getTpl would always return a template (either form the cache or directly from the AJAX request)?

You can use promise/deferred concept to achieve your needs

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;

}

Then, call your method like this:

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

Since you appear to appear to already be using underscore/lodash, you can make use of memoization rather than maintaining your own cache.

The beauty of promises is that you can access them again and again and they will always produce the same value:

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

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

Yes, it really is that simple.

Then you can just use it like any other promise:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM