首页 > 解决方案 > 如何使用异步等待和对反应流的突变对命令式代码进行建模

问题描述

    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();

以上是我的代码的简化版本。我使用命令式编码风格实现了这一点。现在我想把它变成反应流。我怎么做?

我试过这样的事情:

// 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]);
}

当我上面的代码运行时,这是输出:

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

我想我的目标是以功能样式产生相同的输出。

标签: javascriptrxjsreactive-programmingbacon.js

解决方案


我主要取消了您对此的评论,如果有任何需要澄清的地方,请告诉我。我正在使用我的图书馆中的一些方法。pipe只是将函数链接在一起,如果它们是异步的,则等待它们,tap将调用您传递的函数并忽略输出,返回输入

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>


推荐阅读