1

I am new to next(), done() etc. and am struggling with propagating parameters between serial executions/chaining of possibly otherwise asynchronous functions.

I want to force serial execution of 2 functions so they can be called with something like either:

f1('#{arg1a}', '#{arg1b}').done(
  f2('#{arg2a}', '#{arg2b}')
);

OR something like:

f1('#{arg1a}', '#{arg1b}', '#{arg2a}', '#{arg2b}').done(f2);

Where the arg values passed in are gleaned from query parameters using JSF.

Note that:

  • arg2a and arg2b are in my case completely unrelated to arg1a and arg1b, and the invocation of f2 does NOT depend in any way on what happens in f1, other than it must execute strictly afterwards, even if f1 is otherwise usually asynchronous.

  • I am not defining on-the-fly anonymous functions or such inside done() here (yet), I want to be able to call a library-defined function with some known params.

In this example, the functions would be something like:

function f1(arg1a, arg1b) {

   //do something with arg1a, arg1b

  return $.Deferred().resolve();
}

function f2(arg2a, arg2b) {
  // Do something with arg2a and arg2b AFTER f1 has fully run.
}

OR something like:

function f1(arg1a, arg1b, arg2a, arg2b) {

   //do something with arg1a, arg1b

  // Somehow ensure f1 is finished then execute f2(arg2a, arg2b)
}

function f2(arg2a, arg2b) {
  // Do something with arg2a and arg2b AFTER f1 has fully run.
}

Just using callback chaining did not work for the situation I am tackling. See also: How link to and target/open a p:tab within an p:accordionPanel within a p:tab within a p:tabview

An acceptable answer MUST permit me to have a pre-defined function f2 with pre-defined parameters

Community
  • 1
  • 1
  • `return $.Deferred().resolve()` makes no sense because you're calling resolve synchronously in which case you wouldn't even need to handle this async. Are you using an asynchronous function inside `f1`? – slebetman Sep 27 '16 at 07:02
  • Also, can you give a **synchronous** example of what you're trying to do. Something along the lines of "if this was synchronous I'd want to do this..." – slebetman Sep 27 '16 at 07:06

2 Answers2

1

You need to pass parameters to .resolve(), then use .then()

function f1(arg1a, arg1b) {

  return $.Deferred(function(dfd) {
    //do something with arg1a, arg1b
    // you can alternatively call `.resolve()` without passing parameters
    // when you are finished doing something with `arg1a`, `arg1b`,
    // which should call chained `.then()` where `f2` is called
    dfd.resolve(arg1a, arg1b)
  }).promise();
}

function f2(arg2a, arg2b) {
  // Do something with arg2a and arg2b AFTER f1 has fully run.
}

f1(arg1, arg2)
.then(function() {
  // call `f2` here
  f2('#{arg2a}', '#{arg2b}');
})
// handle errors
.catch(function(err) { // alternatively use `.fail()`
  console.log(err)
});

jsfiddle https://jsfiddle.net/wuy8pj8d/

guest271314
  • 1
  • 15
  • 104
  • 177
  • I don't see how you've passed real values for arg2a and arg2b (to be ultimately handled by `f2`) into `f1(arg1, arg2).then(f2) ...` – Webel IT Australia - upvoter Sep 27 '16 at 06:46
  • _"I don't see how you've passed real values for arg2a and arg2b"_ What do you mean? You can pass any value that you need to to `.resolve()` – guest271314 Sep 27 '16 at 06:52
  • `arg2a` and `arg2b` are in my case completely unrelated to `arg1a` and `arg1b`. When you invoke `f1(arg1a,arg1b).then(f2) .. ` there is no moment where the values gleaned from say JSF parameters for arg2a, arg2b are injected. They don't even appear in your calling/invoking code. – Webel IT Australia - upvoter Sep 27 '16 at 06:55
  • _"arg2a and arg2b are in my case completely unrelated to arg1a and arg1b"_ Again, you can pass any value that you need to, or no value, to `.resolve()`; when `.resolve()` is called chained `.then()` is called with `f2` as parameter. You included parameters at `f2`, though they do not need to be the values returned from `f2` The values do not have to be `arg1a`, `arg1b`. The jsfiddle is to demonstrate pattern to meet requirement described at original Question _"the invocation of f2 does NOT depend in any way on what happens in f1, other than it must execute strictly afterwards"_ – guest271314 Sep 27 '16 at 07:00
  • 1
    Thanks, accepted now you've edited it to correctly handle and demonstrate calling of additional arguments for feeding to `f2` (and so it makes sense for other readers to follow). I hit this `.then(...).catch is not a function` in my system, so I used `fail()` then it ran. The `then()` strategy does not solve [my real world app Primefaces nested tab problem](http://stackoverflow.com/questions/39716981/how-link-to-and-target-open-a-ptab-within-an-paccordionpanel-within-a-ptab-wi), but your solution enabled me to at least test the strategy (and learn more about then() and Promises). – Webel IT Australia - upvoter Sep 27 '16 at 07:28
1

You've almost got it right except you've forgotten to wrap the code you want to execute in the future (when done is eventually called) inside a function:

f1('#{arg1a}', '#{arg1b}').done(function(){
  f2('#{arg2a}', '#{arg2b}')
});

This also works with regular callbacks. For example, say you've defined f1 to accept a callback instead of a promise, you'd then do:

f1('#{arg1a}', '#{arg1b}',function(){
  f2('#{arg2a}', '#{arg2b}')
});

Nothing special here. There's no separate syntax for forcing callbacks to accept custom arguments, just wrap it in another function.

This also works for variables thanks to closures:

var a='#{arg1a}', b='#{arg1b}';
var c='#{arg2a}', d='#{arg2b}';

f1(a,b).done(function(){
  f2(c,d)
});

The variables c and d will be accessible within done().

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks for your alternative answer, which definitely (like the amended alread-accepted answer from @guest271314) makes the values for `f2` available to it fine. However, as with `next(` and the `callback` approach, in my [real problem involving a Primefaces web app](http://stackoverflow.com/questions/39716981/how-link-to-and-target-open-a-ptab-within-an-paccordionpanel-within-a-ptab-wi), the `done(` after `f2` is running before `f1` is finishing, so certain selectors are failing (because they are not yet available for selection). But that's beyond the scope of this question here. – Webel IT Australia - upvoter Sep 28 '16 at 03:28
  • @WebelITAustralia-upvoter: The problem with that question is that you're calling the `callback` before whatever you're waiting for is done. Therefore it doesn't work. The point of a callback is so that you can pass it to the thing you are waiting for. If that thing does not provide you with a callback or promise then you have to resort to using `setTimeout` to poll the DOM and wait until the thing you're waiting for exist. – slebetman Sep 28 '16 at 03:49