在回流中排队异步动作

时间:2016-04-29 14:06:00

标签: asynchronous refluxjs

当使用具有异步操作的RefluxJS商店时,您可以轻松地在您的操作之间设置竞争条件。

问题的抽象描述

例如,我们的商店处于状态X.异步操作A从X调用,在完成之前,还会从X调用另一个异步操作B.从此处,无论哪个操作首先完成,它都会错。

  1. B首先以状态Y1结束,A结束并用Y2覆盖状态Y1。
  2. A首先以状态Y2结束,B用Y1覆盖Y2。
  3. 期望的行为是:

      A    B
    X -> Y -> Z
    

    其中B不是基于X,而是基于Y,并且导致一致的Z状态,而不是基于相同状态的两个动作,导致状态不一致:

      A   
    X -> Y1   .--> Y2
      \      /  
       '----'
         B
    

    已实施问题示例

    我写了一个与Node一起运行的最小工作示例,我正在谈论的问题。

    var Q = require('q');
    var Reflux = require('reflux');
    var RefluxPromise = require('reflux-promise');
    Reflux.use(RefluxPromise(Q.Promise));
    
    var AsyncActions = Reflux.createActions({
        'add': { asyncResult: true }
    });
    
    var AsyncStore = Reflux.createStore({
        init: function () {
            // The state
            this.counter = 0;
    
            AsyncActions.add.listenAndPromise(this.onAdd, this);
        },
    
        // Increment counter after a delay
        onAdd: function(n, delay) {
            var that = this;
            return apiAdd(this.counter, n, delay)
            .then(function (newCounter) {
                that.counter = newCounter;
                that.trigger(that.counter);
            });
        }
    });
    
    // Simulate an API call, that makes the add computation. The delay
    // parameter is used for testing.
    // @return {Promise<Number>}
    function apiAdd(counter, n, delay) {
        var result = Q.defer();
    
        setTimeout(function () {
            result.resolve(counter + n);
        }, delay);
    
        return result.promise;
    }
    
    // Log the store triggers
    AsyncStore.listen(console.log.bind(undefined, 'Triggered'));
    
    // Add 3 after 1 seconds.
    AsyncActions.add(3, 1000);
    // Add 100 almost immediately
    AsyncActions.add(100, 1);
    
    // Console output:
    // > Triggered 100
    // > Triggered 3
    
    // Desired output (queued actions):
    // > Triggered 3
    // > Triggered 103
    

    在package.json

    中使用这些依赖项
    {
      "dependencies": {
        "q": "^1.3.0",
        "reflux": "^0.3",
        "reflux-promise": "^1"
      }
    }
    

    问题的性质

    我希望RefluxJS对行动进行排队,但事实并非如此。所以我正在寻找一种正确订购这些行为的方法。但即使我设法以某种方式排队这些动作(因此B在A之后发出)我怎么能确定,当A完成时,发布B仍然是一个有效的动作? 也许我首先以错误的方式使用RefluxJS,这种情况不会发生在结构合理的应用程序中。

    排队异步操作(假设这在Reflux应用程序中是可能的)解决方案?或者,我们是否应该首先以某种方式避免这些情况?

1 个答案:

答案 0 :(得分:0)

你的例子似乎更像是一个关于&#34;真理来源&#34;的概念的问题。比什么都重要。您只在客户端存储数字的当前状态,但只有在收到服务器端对其进行的操作的确认后才更新它。

当然,这会产生问题。你以一种奇怪的方式将数字和数字存储的动作混合起来,在任何特定时刻,数字都不是单一的真实来源。在行动被宣告结束的时间之间处于不确定状态......这是不合适的。

要么存储号码客户端,并且每次添加它,直接添加到该号码然后告诉服务器端新号码是什么...(即客户端承担责任作为事实的来源对于客户端运行时的数字)

或者存储号码服务器端,每次通过客户端的操作启动它时,服务器都会返回新的更新号码。 (即数字的真实来源完全是服务器端)。

然后,即使出现种族问题,您仍然可以获得该数字的真实来源,并且可以检查和确认该来源。例如,如果服务器端拥有该数字的真实来源,那么API也可以在每次返回时返回该值的状态的时间戳,并且您可以根据从API获得的最后一个值来检查它。确保您使用最新值。