12

Lets say I want to process some tasks in the synchronous manner, so I have this function:

function executePromiseQueueSync(queue){
    var seed = $.Deferred(),
        finalPromise;

    finalPromise = _.reduce(queue, function(memo, promise){
        return memo.then(function(){
            return promise.funct.apply(null, promise.argmnt);
        });
    }, seed.promise());

    seed.resolve();
    return finalPromise;
}

Now I can use it to process some files:

_.each(fileList, function(element, index, list){
    _.each(element, function(el, idx, lst){
        promisesQueue.push({funct: processFile, argmnt:[el, index + (len - fileList.length) ,len]});
    });
});

Execute it and indicate a progress:

executePromiseQueueSync(promisesQueue).then(function(){
   ....
}, function(){
    ....
}).progress(function(msg, progress, name, index, status, desc){
        console.log('progress');
});

Process function itself looks like this:

function processFile(file, index, size)
{
    var dfd = new jQuery.Deferred();
    if (file.name.match('(.*)\\.jpg'))
        ...
    else if
        ...
    else
       $.when(processWrongFileType(file)).then(function(){
         dfd.notify(...);
         dfd.resolve();
      });

    return dfd.promise();
}

as you see there is nothing much to do when the file has a wrong type:

So sometimes I would like to execute synchronous code just like a promise:

function processWrongFileType(){
    var dfd = new jQuery.Deferred();
    dfd.resolve();
    console.log("blah");
    return dfd.promise();
}

The problem is if processWrongFileType will be executed, notify will not work. If I change processWrongFileType to look like this:

function processWrongFileType()
{
    var dfd = new jQuery.Deferred();
    setTimeout(function(){dfd.resolve();},1);
    return dfd.promise();
}

notify() will work. Is there any way to avoid setTimeout and still have notify() working with progress event?

mnowotka
  • 16,430
  • 18
  • 88
  • 134
  • Can you show a more complete example of your $.when using x? – Kevin B Apr 05 '13 at 15:39
  • 2
    What you are doing should work... http://jsfiddle.net/3XD9v/ I'm guessing the reason it's not working for you is related to the way you are combining the snippets above, or code around it. – Kevin B Apr 05 '13 at 15:41
  • 4
    Why would you even resolve it before returning the promise? Are you sure you're not just looking for a callback function, as this does'nt make much sense to me ? – adeneo Apr 05 '13 at 15:41
  • @KevinB - I hope this explanation will be clear enough for you. – mnowotka Apr 05 '13 at 15:52
  • @adeneo - I change my question to present the whole problem. – mnowotka Apr 05 '13 at 15:52
  • @adeneo I think the idea is that someFunc could sometimes be deferred and sometimes not. – Christophe Apr 05 '13 at 15:54
  • @Christophe - exactly that! – mnowotka Apr 05 '13 at 15:55
  • @mnowotka Why not just execute `processWrongFileType` outside of the $.when? why does it need to be inside of $.when? unless you're redefining that function to either be sync or async depending on x – Kevin B Apr 05 '13 at 15:57
  • 2
    @mnowotka Still Kevin B is right, it does work. Check out his jsFiddle. – freakish Apr 05 '13 at 15:57
  • @KevinB - processWrongFileType() returns promise itself so id doesn't have to be wrapped with $.when(...) - I agree. But even if you write processWrongFileType(file).then(...) it still won't work. – mnowotka Apr 05 '13 at 16:00
  • But why? If it's not the right filetype, why not just resolve the promise? Why use when, then, another function etc. to resolve the first promise if it's the wrong filetype? That regex won't become async no matter how much you want it to! – adeneo Apr 05 '13 at 16:01
  • That's not what i'm saying. Why does it have to return a promise at all? You're using it alone, it mightaswell just be a function that you execute. – Kevin B Apr 05 '13 at 16:01
  • @KevinB - I was waining for that question. In this particular case it doesn't even have to return a promise but can you think of some situation when you don't know in advance if the function will be synchronous or not but for convenience you would like to have it wrapped in promise? I can give another example but I don't want to have this question be too long. – mnowotka Apr 05 '13 at 16:04
  • 1
    @KevinB because it's sometimes deferred and sometimes not. (I'd say the idea is similar to DOM ready functions). – Christophe Apr 05 '13 at 16:05
  • That i can understand. But my original comment still stands. It works for me! – Kevin B Apr 05 '13 at 16:05
  • My example is bit more complex than yours. I quess problem might be in the executePromiseQueueSync function but I don't know why... – mnowotka Apr 05 '13 at 16:09
  • @KevinB - in my case minimal example would look like this: http://jsfiddle.net/sJcSg/ but I don't know how to include underscore.js and jquery at once... – mnowotka Apr 05 '13 at 16:16
  • Like this: http://jsfiddle.net/sJcSg/1/ – Kevin B Apr 05 '13 at 16:17
  • @KevinB - perfect! And we have a problem now - there is now 'progress' in the console, right? – mnowotka Apr 05 '13 at 16:19
  • @mnowotka Right, and there's also no .notify call, so that makes sense. – Kevin B Apr 05 '13 at 16:21
  • @KevinB - sure, lets add notify then: http://jsfiddle.net/XSDVX/1/ – mnowotka Apr 05 '13 at 17:32
  • That's still a completely different case. The notify is being placed on a different deferred object than the one that you are binding to the progress event of. – Kevin B Apr 05 '13 at 17:40
  • @KevinB - but using setInterval() works: http://jsfiddle.net/UXSbw/ – mnowotka Apr 05 '13 at 17:53
  • @mnowotka did you mean http://jsfiddle.net/UXSbw/1/ – Kevin B Apr 05 '13 at 17:56
  • 2
    To the api. Reading this line *"Any calls to .notify() after a Deferred is resolved or rejected (**or any progressCallbacks added after that**) are ignored."* makes me wonder if since it is already resolved, the inner workings of .then can't bind to the progress event, thus losing the notify all together. – Kevin B Apr 05 '13 at 17:58
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27659/discussion-between-kevin-b-and-mnowotka) – Kevin B Apr 05 '13 at 18:02
  • @KevinB - yes, your modification is also fine but still I can't draw any conclusion here. Yes, I know this fragment from API documentation and this fragment along with your latest code snippet is the essence of my question. Is is possible to achieve similar effect without setInterval? – mnowotka Apr 05 '13 at 18:02
  • Two points: (1) I think "notify will not work" isn't quite correct. I believe that `.notify()` works fine **but** at the time it is called, there's no `.progress()` handler in place to respond. As it says in the documentation, "any calls to .notify() after a Deferred is resolved or rejected (or any progressCallbacks added after that) are ignored." (2) There is little or no point in employing a pseudo-asynchronous pattern for `processWrongFileType()`. Instead use `else { processWrongFileType(file); dfd.resolve('wrongFile'); }`, where 'wrongFile' is an indication of the resolving condition. – Beetroot-Beetroot Apr 07 '13 at 23:13
  • 1
    If you really must have an asynchronous pattern with prog notification for wrong file types, then you must either (a) put the `.progress()` handler in place before calling `.notify()` or (b) ensure that `processWrongFileType()` is a genuinely asynch process, and resolution of the deferred in a `setTimeout()` is a perfectly reasonable approach (otherwise it pretty well has to be a dummy HTTP request). If you don't like to see a `setTimeout()` in the code at that point, then create a function, say `pseudo_asych()`, containing the timeout, which takes the dfrd to be resolved as an argument. – Beetroot-Beetroot Apr 07 '13 at 23:26
  • 1
    It looks like you're attempting to implement a .progress() style event/handler by constantly publishing and resolving promises, rather than what they're designed for: calling .notify() on a single promise over and over again, and then .resolve() just the once at the very end, when everything really is done. – Chris Moschini Apr 08 '13 at 07:33
  • See here http://stackoverflow.com/questions/15840865/timing-issues-with-jquery-deferred/16496232#16496232 – basos May 11 '13 at 11:05

1 Answers1

1

You dont need to do anything special in order to use sync code as promise.

Just return value that is ==true

$.when((function() {
    return prompt('really?')
})()).then((function() { 
    return alert('yeah') 
})()).done((function () { 
    alert('done') 
})())
vittore
  • 17,449
  • 6
  • 44
  • 82