8

I need a method to fetch different scripts with a callback. This method works ok:

fetchScripts:function() {
    var _this=this;
    $.when(
        $.ajax({
            url:_this.url + 'library/script-one.js',
            type:'get',
            cache:true
        }),
        $.ajax({
            url:_this.url + 'library/script-two.js',
            type:'get',
            cache:true
        }),
        { .... },
        $.ajax({
            url:_this.url + 'library/script-n.js',
            type:'get',
            cache:true
        })
    ).then(function() {
        console.log('fetch is done');

    })
},

But i'd like to more generalize the method because redundany is increasing. Is it possible to pass a promise to $.when()? Below my first attempt - but url is always the same, i.e. 'script-n.js' Maybe i missed the point and you could illustrate a more "beauty" solution

fetchScripts:function() {
    this.deferred=new $.Deferred();
    this.promise=this.deferred.promise();
    var _this=this;
    $.each([
        'script-one.js',
        'script-two.js',
        ( .... ),
        'script-n.js'
    ],function() {
        _this.script=this;
        _this.promise.then(function(){
            return $.ajax({
                url:_this.url + 'library/' + _this.script,
                type:'get',
                cache:true
            })
        });
    });
    $.when(
        this.promise
    ).then(function() {
        console.log('fetch is done');

    });
    this.deferred.resolve();
},
campari
  • 985
  • 2
  • 8
  • 11

2 Answers2

28

You still need $.when. But instead, create an array of Deferreds (or promises) and then apply it to $.when:

fetchScripts:function() {
    var base = this.url;
    var defaults = {
        type:'get',
        cache:true
    };

    var libraries = [
        'library/script-one.js',
        'library/script-two.js',
        'library/script-n.js'
    ];

    var deferreds = $.map(libraries, function(current) {
        var ajaxOptions = $.extend({ url:  base + current }, defaults);
        return $.ajax(ajaxOptions);
    });

    $.when.apply($, deferreds).then(function() {
        console.log('All done');
    });
}

Alternatively to extending the default settings, you could just use $.ajax(defaults).

Daff
  • 43,734
  • 9
  • 106
  • 120
  • To access the results of the deferred values you can use the `arguments` magic variable inside the anonymous function passed to `.then`; – Sverri M. Olsen Jun 08 '15 at 12:12
  • 1
    I've noticed that when using then(), if any of the request fails, you will enter its function despite not being all done, whereas with done(), it will only be executed when the last one to remain is finished, no matter if some fail. – Luis Martin Apr 29 '16 at 19:23
4

Try

fetchScripts: function() {
    var deferred = new $.Deferred();
    var _this=this;

    var promises = $.map([
        'script-one.js',
        'script-two.js',
        ( .... ),
        'script-n.js'
    ], function(item, idx) {
        return $.ajax({
            url:_this.url + 'library/' + item.script,
            type:'get',
            cache:true
        })
    });

    $.when.apply($, promises).then(function() {
        console.log('fetch is done');
        deferred.resolve()
    });
    return deferred.promise();
}
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531