在回流中排队异步操作
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 获得的最后一个值进行检查确保您实际使用的是最新值。
【讨论】:
以上是关于在回流中排队异步操作的主要内容,如果未能解决你的问题,请参考以下文章