Question

I've tried to use the jQuery API's example of when() to make an example of my own using timeouts.

Theirs:

$.when( $.ajax( "/page1.php" ), $.ajax( "/page2.php" ) ).done(function( a1, a2 ) {
  // a1 and a2 are arguments resolved for the page1 and page2 ajax requests, respectively.
  // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
  var data = a1[ 0 ] + a2[ 0 ]; // a1[ 0 ] = "Whip", a2[ 0 ] = " It"
  if ( /Whip It/.test( data ) ) {
    alert( "We got what we came for!" );
  }
});

Mine:

var fnOne = function(){

  setTimeout(function(){  return "one";    }, 1000);


};


var fnTwo = function(){

  setTimeout(function(){  return "two";    }, 5);

};


$(function(){

    $.when( fnOne(), fnTwo() ).then(function( a1, a2 ) {

      console.log(a1, a2);

   });


});

I just get undefined undefined. Why won't this work? Incidentally, it works when I remove the timeout. JSBIN.

Was it helpful?

Solution

$.when() requires arguments that are a deferred or promise. It will then resolve itself when all those promises passed as arguments are resolved. When you pass it something that is not a promise, $.when() really has no idea when it's done so can't do it's job.

If you really want to use setTimeout() with the promises API, then you probably want to wrap it so that it returns a promise that is resolved after the timer fires. Then, you can use it just like the $.ajax() calls.

Here's a promise wrapper for setTimeout(). It returns a promise that is resolved after the timer has fired and the callback has been called and the value it is resolved with is the return value from the callback:

function promiseSetTimeout(fn, t) {
    var d = $.Deferred();
    setTimeout(function() {
        d.resolve(fn());
    }, t);
    return d.promise();
}

Then, you could use promiseSetTimeout() with $.when():

function fnOne() {
     return promiseSetTimeout(function(){  return "one";    }, 1000);
}

function fnTwo() {
     return promiseSetTimeout(function(){  return "one";    }, 1000);
}

$.when( fnOne(), fnTwo() ).then(function( a1, a2 ) {
  console.log(a1, a2);
});

Working demo: http://jsfiddle.net/jfriend00/HskLh/

OTHER TIPS

Why won't this work?

Because fnOne and fnTwo don't return a promise, they return undefined. The functions should look like:

var fnOne = function(){
  var deferred = new $.Deferred();

  setTimeout(function(){  deferred.resolve("one")   }, 1000);

  return deferred;
};

Otherwise, if you pass any other value than a promise to $.when, it will automatically create a resolved promise with that value. Also, returning a value from the callback you pass to setTimeout doesn't have any effect on the function that calls setTimeout.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top