【发布时间】: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 应用程序中是可能的)是解决方案吗?还是我们应该首先以某种方式避免这些情况?
【问题讨论】:
标签: asynchronous refluxjs