由于竞争条件,MobX 操作计划/执行顺序未保留



这是我到目前为止所拥有的运行示例:

https://codesandbox.io/s/github/brucel33t/mobx-action-synchronous-execution-ectry/tree/tree/master/

store.js

import { observable, action } from "mobx";
import Sensor from "../models/Sensor";
export default class RootStore {
  @observable sensors = new Map();
  constructor() {
    let self = this;
    const sensorIds = [
      "sensor1",
      "sensor2",
      "sensor3",
      "sensor4",
      "sensor5",
      "sensor6",
      "sensor7",
      "sensor8",
      "sensor9",
      "sensor10"
    ];
    for (let sensor of sensorIds) {
      self.sensors.set(sensor, new Sensor(5));
    }
    // setInterval simulates some incoming data (originally from SignalR, and roughly each second)
    setInterval(function() {
      let out = {};
      const x = +new Date(); // unix timestamp
      for (let sensor of sensorIds) {
        const y = Math.floor(Math.random() * 10000) + 1;
        const m = { x: x, y: y };
        out[sensor] = m;
      }
      self.addMeasurement(out); // the problem starts here.
    }, 1000);
  }
  // the problem!
  @action
  addMeasurement(sensorMeasurementMap) {
    let self = this;
    // this timeout is to try and simulate a race condition
    // since each measurement is incoming each second,
    // here some of them will take as long as 6 seconds to add,
    // due to the timeout.
    // the point is that they should always be added,
    // in the order they were called in.
    // so if the first measurement takes 20 seconds to be added,
    // the next measurements that were received on 2, 3, 4, 5..., 19th second etc,
    // should all "wait" for the prev measurement, so they're added
    // in the right order (order can be checked by timestamp, x)
    setTimeout(() => {
      const keys = self.sensors.keys();
      if (keys.length === 0) {
        // never really gonna happen, since we already set them above
      } else {
        for (const key in sensorMeasurementMap) {
          if (self.sensors.keys().indexOf(key) > -1) {
            self.sensors.get(key).add(sensorMeasurementMap[key]);
          } else {
            // also not gonna happen in this example
          }
        }
      }
    }, Math.floor(Math.random() * 20 + 1) * 1000);
  }
}

Sensor.js

import Queue from './Queue';
import {observable, action} from 'mobx';
export default class Sensor {
  @observable queue;
  constructor(n) {
    this.n = n;
    this.queue = new Queue(this.n);
  }
  @action add(measurement) {
    this.queue.add(measurement);
  }
}

queue.js

import {observable, action} from 'mobx';
export default class Queue {
  @observable data;
  constructor(maxSize) {
    this.maxSize = maxSize;
    this.size = 0;
    this.data = [];
  }
  @action add(measurement) {
    let removedItem = undefined;
    if(this.size >= this.maxSize) {
      let temp = this.data[0];
      removedItem = temp && temp.y ? temp.y+'' : undefined;
      this.data.shift();
    }
    this.data.push(measurement);
    if (removedItem === undefined && this.size < this.maxSize) {
      this.size++;
    }
    return removedItem;
  }
}

代码中有几个注释,但您绝对需要查看https://codesandbox.io/s/github/brucel33t/mobx-action-synchronous-execution-execution-eccution-eccution-eccution-eccution-eccution-ecre/tree/master/了解它。

让我也尝试在这里解释,这是什么。

这基本上是真实应用程序的一部分的过度简化版本,其中SetInterval仅用于模拟Signalr事件处理程序,以指示每秒传入的数据。传入数据是我们在addmeasurement action上方的setInterval func中创建的。

因此,鉴于每秒收到一些传入数据,我们想将其添加到商店上可观察到的地图传感器中。由于此数据用于实际应用程序中的绘制图表,因此我们需要确保确实以调用操作的顺序添加它 - 无论操作需要多长时间完成。

在实际应用程序中,我看到了如何将数据推向MOBX状态的顺序,因此我将其隔离并将相关部分提取到了此示例中,并试图通过使用内部的SetteMeTUt func来夸大它添加措施。

由于每个数据每秒都会获取,但是某些测量可能需要20秒才能获取(不是现实的,但要清楚地显示种族条件问题(,因为该代码目前是在类似:

[
    {"x":1519637083193,"y":4411},
    {"x":1519637080192,"y":7562},
    {"x":1519637084193,"y":1269},
    {"x":1519637085192,"y":8916},
    {"x":1519637081192,"y":7365}
]

实际上永远不会发生,因为 1519637083193 1519637080192 。。。

这是一个真正的问题,当从此数据绘制图表并之后订购的图表太贵了,因此我正在寻找一种改进此代码的方法完成的。或至少一种以正确顺序更新MOBX状态的方法

希望这是有道理的。

应该所有"等待"上一个上的测量,因此它们以正确的顺序添加(可以通过Timestamp,x检查订单(。

您能详细说明吗?怎么会知道,将来不会收到比当前收到的时间戳,因此无限期地等待呢?您不是只在寻找一系列测量的插入(而不是等待(吗?

如果排序的插入无法解决问题,我可能会执行以下(未经测试(:

lastAddition = Promise.resolve() // start with already finishied addition
addMeasurement(sensorMeasurementMap) {
      this.lastAddition = this.lastAddition.then(() => {
          return new Promise((resolve, reject) => {
            setTimeout(action(() => {
                const keys = self.sensors.keys();
                if (keys.length === 0) {
                    // never really gonna happen, since we already set them above
                } else {
                    for (const key in sensorMeasurementMap) {
                    if (self.sensors.keys().indexOf(key) > -1) {
                        self.sensors.get(key).add(sensorMeasurementMap[key]);
                    } else {
                        // also not gonna happen in this example
                    }
                    }
                }
                resolve()
            }), Math.floor(Math.random() * 20 + 1) * 1000);
        })
      })
  }
}

n.b。:请注意,我需要将action移到内部,因为您需要在实际修改状态的地方,而不是调度发生的地方

最新更新