Conditional promises

2019-06-18 15:34发布

问题:

In my script, I need to retrieve a dictionary to convert encoded values into names:

$.ajax({
    // retrieve dictionary
})
.done(function(dictionary){
    // convert encoded values into names
})
.done(function(){
    // run my application
});

However, sometimes the dictionary has already been loaded by another application, and in this case I don't need the ajax call:

if (dictionary) {
    // convert encoded values into names
    // run my application
}
else {
$.ajax({
    // retrieve dictionary
})
.done(function(dictionary){
    // convert encoded values into names
})
.done(function(){
    // run my application
});
}

This if/else statement is rather heavy, is there a way to make it shorter:

// load dictionary if needed
// then run my application

Note: I used the $ sign for my pseudo-code, but I am not necessarily tied to jQuery.

回答1:

Maybe create a bogus promise with $.when?

var promise;
if (dictionary) promise = $.when(dictionary);
else {
    promise = $.ajax({

    })
    .done(function(dictionary){
        // convert encoded values into names
    });
}

promise
    .done(function(){
        // run my application
    });


回答2:

This is the pattern I generally use:

var done = function() {
    //continue loading application
}

if(!dictionary) {
    $.ajax({

    })
        .done(done);
} else {
    done.apply(this);
}

A very similar pattern, that always makes use of a deferred object, could be the following:

var 
    dictionaryDeferred = new $.Deferred(),
    dictionaryPromise = dictionaryDeferred.promise();

if(!dictionary) {
    $.ajax({

    })
        .done(function() {
            //do something with the response
            dictionaryDeferred.resolve();
        });
} else {
    dictionaryDeferred.resolve();
}

dictionaryPromise.then(function() {
    //continue loading application
});


回答3:

You should call $.ajax() exactly once, and store the returned promise in your (global-ish) dictionary variable.

Then, every time you want to use the result, just write dictionary.then(...).
If the AJAX request already finished, the callback will run immediately.