Hey Scott,

I feel that flow-control is the future of JavaScript, and love that
you're embracing deferreds. I think folks are beginning to realize
that you can't trust functions - so constructs must evolve in order to
control their execution. Anyway, your flow function looks concise and
elegant.

I am still working on that walk-thru - trying to keep it simple - but
would like to apply Flow to your current project: calling multiple
asynchronous tasks in any order. I'll go over a few ways you can do
that with Flow.

For simple flow-control, Flow provides .go() and .wait() methods.

var ajaxCalls = new Flow({
  ajax1: function () {
    var flow = this;
    flow.wait(); // pause the flow
    doAjax1({
      onComplete: function () {
        flow.go(); // resume the flow
      }
    });
  },
  ajax2: function () {
    var flow = this;
    flow.wait(); // pause the flow
    doAjax2({
      onComplete: function () {
        flow.go(); // resume the flow
      }
    });
  },
  ajaxN: function () {
    var flow = this;
    flow.wait(); // pause the flow
    doAjaxN({
      onComplete: function () {
        flow.go(); // resume the flow
      }
    });
  },
  // ... etc
});

We can now "go to" any number of states in our Flow...

  Flow(ajaxCalls).go('ajax2', 'ajax1', ..., 'ajaxN');
  // if ajaxCalls were an instance -> ajaxCalls.go(...);

...Or just one...

  Flow(ajaxCalls).go('ajax1');
  // same as calling "doAjax1()" directly

["Flow(ajaxCalls)" returns an instance with the .go() method.
"ajaxCalls" would already be an instance, if we had initialized it
with the "obj" parameter set to true. See all the parameters at
https://github.com/bemson/Flow/wiki/Flow-API#s2 ]

So that's how to use Flow as a simple utility for sequencing
executions; very much like the flow-js project I mentioned earlier. I
do recommended this usage if you want to integrate Flow slowly,
starting with light execution control. Your functions don't need to
change to work with Flow in this manner.

Of course, invoking a sequence of asynchronous calls may not make
sense. In order to choose the next ajax dynamically, we'll parse the
response and tell Flow where to go next.

var ajaxCalls = new Flow({
  ajax1: function (arg1, arg2) {
    var flow = this;
    flow.wait(); // pause the flow
    doAjax1({
      onSuccess: function (rsp) {
        switch(rsp) {
          case 'ok' :
            // go here next, and set new arguments
            ajaxCalls.ajax2(rsp, arg2, 'Hello World!');
            break;
          case 'maybe':
            // go here next and clear arguments
            flow.target('/ajax3'); // same as "ajaxCalls.ajax3()"
            break;
          case 'noway':
            // go here next, pass original arguments
            flow.go('/ajax4');
            break;
        }
      }
    });
  },
  // ... etc.
});

This Flow is less naive because each state must tell our Flow where to
go - you may not want that level of intelligence baked into your code.
In such cases, you'll likely need to pass arguments around - I've
demonstrated a few techniques. Assuming all the other states did the
same thing, we can now call just one, let it determine which ajax to
call next, and so on.

  ajaxCalls.doAjax1('foo', 'bar');

After this statement, our 'doAjax1' state will direct our Flow to the
next state. All we did was start the chain.

These have been examples of execution-control in Flow. What we have
yet to take advantage of is Flow's state management functionality. For
arguments sake, let's imagine our ajax handlers use a lazy-loaded
debug module and expect a DIV to be available. This kind of shared
functionality can be captured in code using Flow.

var ajaxCalls = new Flow({
  _in: function () {
    var flow = this,
      div = document.createElement('div');
    div.setAttribute('id', 'theDiv');
    document.body.appendChild(div);
    lazyLoadDebugModuleThen(function () {
          // resume towards original target
      flow.go();
    });
    flow.wait();
  },
  ajax1: ...,
  ajax2: ...,
  ajaxN: ...,
  ...
});

Our _in component is assigned to the parent state (in this case, the
root state of the program), and invokes whenever the state or it's
descendants are targeted. If you haven't guessed, _in is a synonym for
"enter" and is a cousin to the before/after advice model of AOP
structures; and who's counterpart is the _out component. Unlike AOP
however, Flow knows where it is in the program, and will not execute
our _in component again until the state is re-entered after exit.
Thus, after calling _in for the first ajax call, subsequent ajax calls
are accessed directly. Above all, none of the ajax calls need to have
logic around their execution environment. This is how Flow works with
changes to logic and process.

In summary, the .go() and .wait() methods can make any function
asynchronous, and state-management plus AOP-style components can
consolidate functional pre-requisites. I encourage you to play with
Flow!

More on these methods at https://github.com/bemson/Flow/wiki/Flow-API#s4.1

- best,

bemson


On Apr 28, 5:25 am, Scott Sauyet <[email protected]> wrote:
> Bemi Faison wrote:
> > Actually, there _is_ another github project called flow-js
> >(https://github.com/willconant/flow-js), which shares the goal of
> > ordered execution.
>
> I hadn't seen that one.  It's a very similar concept to my own,
> although mine uses a declarative syntax.  I have only just done a
> simple proof-of-concept, and that using just jQuery's Deferred/Promise/
> when implementation, but I would like it to work with any Promise/when
> system.
>
> If you're curious, all I have right now is this one simple test page:
>
>    http://scott.sauyet.com/Javascript/Test/2011-04-26b/
>
> We have a system right now where there are four or five AJAX calls
> which need to be made to different services, and they have to be
> composed in different orders in different circumstances.  Luckily, I
> don't have to determine the composition order dynamically, but the
> actual code paths were growing out of hand.  I'm planning on using
> this to clean that up.
>
> The system is limited to functions that accept a single parameter and
> return another of the same type or return a promise that resolves to
> that type.  But this is fairly generic, as it's likely to be something
> of a general state object that's passed around in any case.
>
> > I took a gamble using such a generic term - but
> > otherwise abhor trendy names. Hopefully, my work will be good enough,
> > so folks eying the title won't be too miffed!
>
> I never considered whether the name might be trendy.  It was simply
> descriptive.  It was an extension of another notion we were using of
> "chain", but it was more fluid.  "Flow" just seemed natural.
>
> > [ ... ]
> > I created Flow out of frustration with a complicated web project. I
> > started with clean reusable objects, simple custom-events, and high-
> > level controller functions. Soon, with a looming deadline and many
> > business-rule changes/revelations, I simply needed to "get it done",
> > and wound up inserting logic where ever necessary. The code works
> > today, but I wouldn't wish it upon anyone in the future... including
> > myself.
>
> > [ ... W]e expect requirements to be static, even
> > though they often change. Once we've translated requirements into
> > functionality (e.g., objects and methods), it becomes impractical to
> > update them for every changing requirement - especially when we're far
> > along in the development process. My nightmare project epitomizes how
> > change kills code, and that's because we never code for change.
>
> Although my solution is much smaller in ambition, it has grown out of
> the same frustration you're describing, and over the same problem.
>
> > [ ... ]
> > I hope this helps explain how Flow came about, why it exists, and what
> > gaps it fills. Things are still fuzzy, but it's also my first attempt
> > at explaining things publicly. I fully appreciate (all) your
> > questions! On that note, to best  _demonstrate_ why you should use
> > Flow, I'm writing a walk-thru for the wiki. I'll notify this board
> > when I'm done (tomorrow, hopefully). Many thanks for your attention
> > and patience!
>
> I look forward to seeing that.
>
> Cheers,
>
>   -- Scott

-- 
To view archived discussions from the original JSMentors Mailman list: 
http://www.mail-archive.com/[email protected]/

To search via a non-Google archive, visit here: 
http://www.mail-archive.com/[email protected]/

To unsubscribe from this group, send email to
[email protected]

Reply via email to