在回流中排队异步操作

Posted

技术标签:

【中文标题】在回流中排队异步操作【英文标题】:Queuing asynchronous actions in reflux 【发布时间】:2016-08-24 17:44:58 【问题描述】:

将 RefluxJS 存储与异步操作一起使用时,您很容易在操作之间出现竞争条件。

问题的摘要描述

例如,我们的 store 处于状态 X。从 X 调用一个异步操作 A,在它完成之前,另一个异步操作 B 被调用,也是从 X。从这里开始,无论哪个操作先完成,它都会执行错了。

    B 首先完成状态为 Y1,A 最后完成并用 Y2 覆盖状态 Y1。 A 首先以状态 Y2 结束,B 用 Y1 覆盖 Y2。

期望的行为是:

  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】:

您的示例似乎更像是“真相来源”概念的问题,而不是其他任何问题。您仅在客户端存储号码的当前状态,但只有在收到服务器端对正在执行的操作的确认后才更新它。

这当然会产生问题。您正在以一种奇怪的方式混合对数字的操作和数字的存储,其中在任何给定时刻都没有单一的事实来源。它在动作被称为完成的时间之间处于不确定状态......这不好。

客户端要么存储号码,每次加进去,直接加到那个号码上,然后告诉服务端新号码是什么...(即客户端负责作为真相的来源客户端运行时的数字)

或者在服务器端存储号码,每次您使用来自客户端的操作进行操作时,服务器都会返回新的更新号码。 (即数字的真实来源完全是服务器端)。

那么,即使出现种族问题,你仍然有关于这个数字的真实来源,并且可以检查和确认该来源。例如,如果服务器端持有该数字的真实来源,那么 API 还可以在每次返回该值时返回该值的状态的时间戳,并且您可以将其与从 API 获得的最后一个值进行检查确保您实际使用的是最新值。

【讨论】:

以上是关于在回流中排队异步操作的主要内容,如果未能解决你的问题,请参考以下文章

理解js的同步操作与异步操作

异步操作

javascript:异步操作概述

asp.net mvc 设置一个action的访问人数,达到上线排队

前端异步流程工具

(82)Wangdao.com第十六天1017__ JavaScript 异步操作