如何在 Swing-GUI 和 WebApplication(如 Vaadin 或本机 JS)之间同步倒计时

How to synchronize a countdown between a Swing-GUI and a WebApplication like Vaadin or native JS

我正在尝试将倒计时从 Java 应用程序同步到浏览器。倒计时可以随时停止、开始和重置。

我已尝试在 Vaadin 13 中实现此功能,但无法访问 UI Access Mehtod 来锁定 vaadin 会话。现在我正在尝试使用本机 JS 和 Ajax 请求来实现这一点,但我不确定如何在不每秒发出 ajax 请求的情况下同步 stop/start 和重置事件。

这是计数器的 Swing 实现

public void timer() {

        Timer timer = new Timer(1000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (seconds == 0  && minutes > 0) {
                    minutes--;
                    seconds = 59;   
                } else {
                    seconds--;
                }
                label.setText(minutes+":"+seconds);
                repaint();
            }
        });
        timer.start();

    }

现在我会为 JS 代码提供 Spring 启动休息 API 以询问剩余的分钟和秒数。

setInterval(test, 1000);

async function test() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("GET", "http://10.0.1.17/countdown", false);
    xhttp.send();
    //console.log(JSON.parse(xhttp.responseText));

    //Do Something with it

}

这似乎是一种不可靠且低效的方式

检查此 class,来自

/*
    a (pausable) linear equation over real time

        value = _speed * Date.now() + _offset;

        //when paused, it's simply: 
        value = _offset;

    so basically a clock, a stopwatch, a countdown, a gauge, ...

    since it is only a linear equation over time, it is independant of any interval.
    It computes the value (using Date.now()) whenever you ask for it. Wether this is ever frame or every hour.
*/
class Clock {
    constructor(value=Date.now(), speed=1){
        //state; changes only when YOU set one of the properties (value, paused or speed)
        this._offset = +value || 0;
        this._speed = +speed || 0;
        this._paused = true;

        //preparing a simple hook to get notified after the state has been updated (maybe to store the new state in the localStorage)
        this.onStateChange = undefined;
    }

    get value(){ 
        return this._paused? this._offset: this._speed*Date.now() + this._offset 
    }
    set value(arg){
        let value = +arg || 0;
        let offset = this._paused? value: value - this._speed * Date.now();

        if(this._offset !== offset){
            this._offset = offset;
            if(typeof this.onStateChange === "function") 
                this.onStateChange(this);
        }
    }

    get speed(){
        return this._speed
    }
    set speed(arg){
        let speed = +arg || 0;
        if(this._speed !== speed){
            if(!this._paused)
                this._offset += Date.now() * (this._speed - speed);
            this._speed = speed;
            if(typeof this.onStateChange === "function")
                this.onStateChange(this);
        }
    }

    get paused(){
        return this._paused
    }
    set paused(arg){
        let pause = !!arg;
        if(this._paused !== pause){
          this._offset += (pause? 1: -1) * this._speed * Date.now();
            this._paused = pause;
            if(typeof this.onStateChange === "function")
              this.onStateChange(this);
        }
    }

    time(){
        let value = this.value,v = Math.abs(value);
        return {
            value,
            //sign: value < 0? "-": "",
            seconds: Math.floor(v/1e3)%60,
            minutes: Math.floor(v/6e4)%60,
            hours: Math.floor(v/36e5)%24,
            days: Math.floor(v/864e5)
        }
    }

    valueOf(){
        return this.value;
    }   

    start(){
        this.paused = false;
        return this;        
    }
    stop(){
        this.paused = true;
        return this;
    }
}

我展示这个是因为如果你仔细观察它,你会发现这个东西的整个状态由两个数字和一个布尔值组成,它们只在你做点什么,比如 start/stop 吧。

实际值是根据此状态和计算机内部时钟计算得出的。

因此,如果您在前端和后端之间同步此状态,它们都会运行(大部分)同步。

为什么主要是?因为在另一端收到新状态之前有一点延迟。对于这几毫秒,两者不同步。一旦另一端更新了它的状态,它们就会再次同步。