We imagined a utility that could take two or more generators and run them concurrently, letting them cooperatively yield control from one to the next, with optional message passing.

    In addition to being able to run a single generator to completion, the ASQ#runner(..) we discussed in Appendix A is a similar implementation of the concepts of runAll(..), which can run multiple generators concurrently to completion.

    So let’s see how we can implement the concurrent Ajax scenario from Chapter 4:

    The main differences between ASQ#runner(..) and runAll(..) are as follows:

    • token.messages is an array that holds any messages passed in from the previous sequence step. It’s also a data structure that you can use to share messages between coroutines.
    • The last returned or ed value from the coroutine processing run will be forward passed to the next step in the sequence.

    One example that may be familiar to many programmers is state machines. You can, with the help of a simple cosmetic utility, create an easy-to-express state machine processor.

    Let’s imagine such a utility. We’ll call it state(..), and will pass it two arguments: a state value and a generator that handles that state. state(..) will do the dirty work of creating and returning an adapter generator to pass to ASQ#runner(..).

    Consider:

    If you look closely, you’ll see that state(..) returns back a generator that accepts a token, and then it sets up a while loop that will run until the state machine reaches its final state (which we arbitrarily pick as the false value); that’s exactly the kind of generator we want to pass to ASQ#runner(..)!

    How do we use the helper along with ASQ#runner(..)?

    It’s important to note that the *stateOne(..), *stateTwo(..), and *stateThree(..) generators themselves are reinvoked each time that state is entered, and they finish when you transition(..) to another value. While not shown here, of course these state generator handlers can be asynchronously paused by yielding Promises/sequences/thunks.

    The underneath hidden generators produced by the state(..) helper and actually passed to ASQ#runner(..) are the ones that continue to run concurrently for the length of the state machine, and each of them handles cooperatively yielding control to the next, and so on.

    Note: See this “ping pong” example () for more illustration of using cooperative concurrency with generators driven by ASQ#runner(..).