Search code examples
functional-programmingfrprxjsbacon.js

Complex operation with BaconJS (FRP)


I'm trying to do this relatively complex operation in BaconJs.

Basically, the idea is keep trying each check until you have a 'pass' status or they all fail. The catch is that 'pending' statuses have a list of Observables (built from jquery ajax requests) that will resolve the check. For performance reasons, you need to try each Observable in order until either they all pass or one fails.

Here's the full pseudo algorithm:

  • Go thru each check. A check contains an id and status = fail/pass/pending. If pending, it contains a list of observables.
    • If status = pass, then return the id (you're done!)
    • if status = fail, then try the next check
    • if status = pending
      • try each observable in order
        • if observable result is 'false', then try the next check
      • if reach end of observable list and result is 'true', then return the id (you're done!)

Here's the Bacon code. It doesn't work when the Observables are Ajax requests. Basically, what happens is that it skips over pending checks....it doesn't wait for the ajax calls to return. If I put a log() right before the filter(), it doesn't log pending requests:

    Bacon.fromArray(checks)
      .flatMap(function(check) {

        return check.status === 'pass' ? check.id :
          check.status === 'fail' ? null :
            Bacon.fromArray(check.observables)
              .flatMap(function(obs) { return obs; })
              .takeWhile(function(obsResult) { return obsResult; })
              .last()
              .map(function(obsResult) { return obsResult ? check.id : null; });
      })
      .filter(function(contextId) { return contextId !== null; })
      .first();

UPDATE: the code works when the checks look like this: [fail, fail, pending]. But it doesn't work when the checks look like this: [fail, pending, pass]


Solution

  • I agree with @paulpdaniels Rx-based answer. The problem seems to be that when using flatMap, Bacon.js won't wait for your first "check-stream" to complete before launching a new one. Just replace flatMap with flatMapConcat.