0

I have this code below which is not working as I am expecting.Here GetAllFileNames is Async function and I want to do some sequential action based on result of this funciton. So I am using Jquery promise. But I feel that statement return deferred.resolve(GetAllFileNames) is not correct.It immediately calls promise.then without even waiting for GatAllFileNames to finish.Please note this is not actually working code.

function getfilenames() {
  var deferred = $.Deferred();

  if(condition == true) {
    return deferred.resolve(JSON.parse(allFileNames));
  } else {
    return deferred.resolve(GetAllFileNames());
  }
}    

var promise = getfilenames();      
promise.then(function(fileNames) {
  result.fileNames = fileNames; 
});

UPDATE: I tried some of your comments ,but none of them is working.Here is one of example which is not working

<!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script> $(function () {
    var deferred = $.Deferred();
    var result = {};
    var GetAllFileNames = function () {
        return {
            "allFileNames": [1, 2, 3, 4, 5, 6, 7, 8, 9]
        };
    };

    function getfilenames(condition) {

        if (condition == true) {
            return deferred.notify(JSON.parse(allFileNames));
        } else {
            return deferred.notify(GetAllFileNames());
        }
    };

    deferred.then(
    // `deferred.done`
    function (fileNames) {
        result.fileNames = fileNames;
        $("<span>" + result.fileNames.allFileNames + "</span>")
            .appendTo("body");          console.log(JSON.stringify(fileNames));
    }
    // `deferred.fail`
    ,


    function () {
        console.log(new Error("getfilenames error").message);
    } );

    getfilenames(false);

}) </script> </head> <body>

</body> </html>
anand
  • 11,071
  • 28
  • 101
  • 159
  • 1
    What is method of confirming `GetAllFileNames()` is complete ? Is there `length` property of items to query ? If tasks to perform after `GetAllFileNames()` , could utilize `deferred.notify` to provide notification of `GetAllFileNames()` with `deferred.progress` , then `resolve` `deferred` within `progress` when complete ; which would then call `deferred.then` – guest271314 Aug 26 '14 at 15:22
  • 1
    Just do `function getfilenames() { return condition ? $.when(JSON.parse(allFileNames)) : GetAllFileNames(); }` why all that cruft? Why a deferred? Why a resolve? This is a very messy way to do something simple. – Benjamin Gruenbaum Aug 26 '14 at 16:58
  • @Alien01 Not certain about logic at `if` statement ? , what `condition` is ? , or what expected return value of `getallfilenames` ? Composed with `condition` being `false` ; not certain about `getallfilenames` possible return value(s) ; what `allFileNames` is , if return by function within `getallfilenames` ? See post – guest271314 Aug 26 '14 at 17:43
  • @BenjaminGruenbaum Nice ! See also `$.when(condition ? getfilenames() : GetAllFileNames())` – guest271314 Aug 26 '14 at 17:57
  • 1
    @guest271314 that's even nicer (and closer to what I usually do) :) You should edit your answer to get rid of that [deferred anti pattern](http://stackoverflow.com/questions/23803743/what-is-the-deferred-anti-pattern-and-how-do-i-avoid-it) – Benjamin Gruenbaum Aug 26 '14 at 17:59
  • @BenjaminGruenbaum Interesting reads . Still reviewing . Actually was not going to include `this.resolve()` portion ; for two point 1) not certain about what the exact item to resolve was _expected_ to be ; 2) in this instance , it was the `progress` notifications that appear to be primary goal of task ; or "when x tasks complete , do stuff" ? Is utilizing notify-progress pattern considered an "anti-pattern" ? even if utilizing `deferred` object for the re-usable notify-progress functionality - not to resolve a deferred object , or return a deferred.promise ? Alternatives? Thanks for the light – guest271314 Aug 26 '14 at 18:11
  • @guest271314 progression is a completely broken API that does not compose well, it was deprecated in Q and will not move to V2, it was deprecated in Bluebird and it will not ever make it into ES6 promises - for more information about it see https://github.com/petkaantonov/bluebird/blob/master/API.md#progression-migration - Domenic and KrisKowal have also written about it. If you need to emit multiple events from a promise rather than just completing or failing you should use an event emitter. – Benjamin Gruenbaum Aug 26 '14 at 18:14
  • @BenjaminGruenbaum jquery's version of notify-progress considered broken / perhaps removed from next versions ? Similar was mentioned http://stackoverflow.com/questions/24971676/notify-after-async-task-is-done/, see Answers, comments . Several options for `deferred` or `promises` appear to be available for utilization ? Selection of which to employ depend on composer / adjuster of composition / task to perform ? Could also compose / re-compose deferred/promises/progress , see http://stackoverflow.com/a/23587868/2801559 , http://jsfiddle.net/guest271314/N6EgU ; What would edit post to ? – guest271314 Aug 26 '14 at 18:50
  • @BenjaminGruenbaum I tried to use function getfilenames() { return condition ? $.when(JSON.parse(allFileNames)) : GetAllFileNames(); }, but how can I use .then ,when condition is true. Since it returns a JSON object and not a funtion , so .then wont work in that case. – anand Aug 26 '14 at 22:56

2 Answers2

0

You should resolve the deffered when operation is acutully performed.

In this Example 'Got all files' will be displayed before 'get all files'

Got all file names
Get all files names

function GetAllFileNames(ms) {
    //simulate delay
    setTimeout( function() { console.log('Get all files names') ; return 20;}, ms);
} 

function getfilenames() {

    var def = $.Deferred();

    def.resolve(GetAllFileNames(2000));

    return def;
}

getfilenames().then( function() { console.log('Got all file names'); });

but here console log order would be

Get all file names
Got all file names

function GetAllFileNames(ms, def) {
    setTimeout(function() {
        console.log('Get all file names');
        def.resolve();
        return 20;
    }, ms);
}

function getfilenames() {

    var def = $.Deferred();

    var result = GetAllFileNames(2000, def);

    return def;
}

getfilenames().then(function() {
    console.log('Got all file names');
});

because deffered is resolved when GotAllFilesNames is ready.

SSA
  • 5,433
  • 4
  • 36
  • 50
  • 2
    You shouldn't ever write a function that takes a deferred to fulfill - just merge them into one. It also would make the difference more clear, it's a bit difficult to spot here. – Bergi Aug 26 '14 at 15:24
  • @Bergi, Thanks for note. I thought it's easy to demonstrate that way but could you please explain, why it's shouldn't be done? I'll adjust the demo. – SSA Aug 26 '14 at 15:29
  • 1
    It can be helpful in some rare settings, but in general you're just spreading one functionality over two functions. `getfilenames` doesn't really do very much, creating the promise should be part of the function that actually does the async call. – Bergi Aug 26 '14 at 15:35
  • Thanks again but I thought there was a big drawback you were pointing out with 'shouldn't ever' statement. Anyways it was for example to demonstrate & not actual getallfilenames implementation. About resolving deffered, that's what I exactly said in my answer. – SSA Aug 26 '14 at 21:27
0

Edit, updated ; see comments at Question

Try (this pattern)

 var result = {};
 var GetAllFileNames = function () {
        return {
            "allFileNames": [1, 2, 3, 4, 5, 6, 7, 8, 9]
        };
    };
var getfilenames = function (condition) { // `condition` ?
    return $.when(
             condition 
             ? JSON.parse(allFileNames)
             : GetAllFileNames()
           ); 
    };

    getfilenames(false) // `condition` ?
    .then( 
    // `done`
      function (fileNames) {
        result.fileNames = fileNames;
        $("<span>" + result.fileNames.allFileNames + "</span>")
            .appendTo("body");
    }
    // `fail`
    , function () {
        console.log(new Error("getfilenames error").message);
    });

jsfiddle http://jsfiddle.net/guest271314/9f12san7/

guest271314
  • 1
  • 15
  • 104
  • 177
  • Why do you (try to) use a progress notification to resolve the deferred? – Bergi Aug 26 '14 at 17:23
  • Questions asking for clarifications should go in comments on the original post, not in an answer. – Bergi Aug 26 '14 at 17:25
  • @Bergi Found pattern of utilizing `deferred.notify` and `deferred.progress` for "polling" , or intermediate tasks , practical. Those methods appear rarely utilized at SO Questions . Just a pattern ; progress could be run several times without actually resolving the deferred . If arguments provided to notify-progress meet condition , resolve deferred , there . Issue with utilizing progress callback to notify progress "events" ? , before actually resolving or rejecting a deferred ? Does pattern possess potential issue ? If possible , can illuminate on reason noted pattern ? – guest271314 Aug 26 '14 at 17:39
  • @Bergi Updated. Tried to include detail / description of how arrived at Answer within initial post . Thanks – guest271314 Aug 26 '14 at 17:46
  • This is not working when getfilenamesis called with true condition,getfilenames(true) – anand Aug 26 '14 at 23:07
  • @Alien01 The piece at post composed to _only_ return `false` ; a template , or pattern , to possibly include other pieces or values not included at OP . Not certain about what `condition` is ? Do both `getfilenames` and `GetAllFileNames` return same result ? If possible , could provide descriptions of `condition` , and expected return values of `getfilenames` and `GetAllFileNames` ? Thanks – guest271314 Aug 26 '14 at 23:56
  • Could re-arrange piece to call async function first . If load time excessive , or other "condition", `reject` deferred, which would call `fail` , where non-async `getfilenames` called ? – guest271314 Aug 27 '14 at 00:35
  • Yes, there is an issue with using progress callbacks to resolve a deferred - the progress events are thought to notify *subscribers* of your promise, not to notify yourself. The callbacks should not change the state of your deferred - and usually they only have access to the promise (which they can't resolve) anyway. If you want to use something like this, you at least need to create a *new* promise which represent something like "the first progress event that meets , or the result of the other promise". – Bergi Aug 27 '14 at 11:37
  • @Alien01 If possible , could describe `condition` ? What adjusts `condition` between `true` or `false` ? Is order 1) call `getfilenames` ? which returns ? 2) if `getfilenames` _does not_ return `condition` (`true`) , e.g., `json` object, `GetAllFileNames` is called ? Or , is order reverse of above ? 1) Call `GetAllFileNames` ; if return result `true` (`json`) object ; 2) call `getfilenames` to further process `json` object ? Necessity of redundancy between `getfilenames` and `GetAllFileNames` ? if they return same object ? Thanks – guest271314 Aug 27 '14 at 15:37
  • @Bergi Interesting concepts. Not appear to be an actual _drawback_ to utilizing `deferred.notify` to resolve a `deferred` (< v1.8) ; if the publisher of the notification _permits_ the subscriber to achieve this ? There seem a similar pattern of concepts relating to deferred/promises - particularly jquery's model. Though , the object(s) could be malleable enough to support different concepts; experimentation of the breadth of possibilities ? `notify/progress` _could_ be versatile enough for varying usages ; though could use `$.queue` or `$.Callbacks` for notify; used already internally ? Thanks – guest271314 Aug 27 '14 at 15:57