How to model imperative code with async await and mutations to reactive streams

180 views Asked by At

    let drawer = {};
    let stacks = {};
    
    async function actionDealCard(hidden) {
    
        let previousMutation = drawer.mutation;
        drawer.mutation = true;
    
        await new Promise(resolve => {
            setTimeout(resolve, previousMutation?500:100);
            console.log('animation happening');
        });
        stacks.mutation = hidden;
    }
    
    async function mainFunction() {
        let deals = [1,2,3];
        for (let key in deals) {
            await actionDealCard(key);
        }
        console.log(stacks, drawer);
    }

mainFunction();

Above is the simplified version of my code. I implemented this using imperative coding style. Now I want to turn this into reactive streams. How do I do that?

I've tried something like this:

// I need an event stream that describes when to mutate drawer
// to pass to DrawerProperty function
// This might be a bus to simplify the solution but buses are bad.
let esDrawerMutate = ???

let drawer = DrawerProperty(esDrawerMutate);

async function actionDealCard(key) {
  // I have no clue what's going on here
}


let deals = Bacon.fromArray([1,2,3]);

let esMain = deals.flatMap(key => {
    return Bacon.fromPromise(actionDealCard(key));
});

esMain.log();

function DrawerProperty(esMutate) {
    return Bacon.update({},
        [esMutate, _ => _.mutation = true]);
}

function StacksProperty(esMutate) {
    return Bacon.update({},
        [esMutate, _ => _.mutation = true]);
}

When my above code run this is the output:

animation happening
animation happening
animation happening
{
  "mutation": "2"
} {
  "mutation": true
}

I guess my goal here is to produce this same output in functional style.

1

There are 1 answers

1
richytong On

I went off your comment for this one mostly, please let me know if anything needs clarification. I'm using some methods from a library of mine. pipe just chains functions together and waits for them if they're async, tap will call the function you pass it and disregard the output, returning the input

const drawer = { cards: [1, 2, 3], did_mutate: false }

const popCardFromDrawer = () => drawer.cards.pop()

const animate = () => {
  console.log('animation happening')
  const animationTime = drawer.did_mutate ? 100 : 500
  drawer.did_mutate = true
  return new Promise(resolve => setTimeout(resolve, animationTime))
}

const stacks = { cards: [] }

const addCardToStacks = card => { stacks.cards.push(card); return stacks }

const { pipe, tap } = rubico

const dealAction = pipe([
  popCardFromDrawer, // () => card
  tap(animate), // card => card
  addCardToStacks, // card => stacks
])

const main = async () => {
  while (drawer.cards.length > 0) {
    await dealAction()
    console.log('drawer', drawer, 'stacks', stacks)
  }
}

main()
<script src="https://unpkg.com/rubico/index.js"></script>