Javascript 如何在Swing GUI和Web应用程序(如Vaadin或native JS)之间同步倒计时

Javascript 如何在Swing GUI和Web应用程序(如Vaadin或native JS)之间同步倒计时,javascript,java,ajax,vaadin,Javascript,Java,Ajax,Vaadin,我正在尝试将Java应用程序的倒计时同步到浏览器。倒计时可以随时停止、启动和重置 我试图在Vaadin 13中实现这一点,但无法访问UI访问方法来锁定Vaadin会话。现在我正试图用原生JS和Ajax请求实现这一点,但我不知道如何在不每秒发出Ajax请求的情况下同步停止/启动和重置事件 这是计数器的Swing实现 公共无效计时器(){ 计时器计时器=新计时器(1000,新ActionListener(){ 已执行的公共无效操作(操作事件e){ 如果(秒==0&&minutes>0){ 分钟--;

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

我试图在Vaadin 13中实现这一点,但无法访问UI访问方法来锁定Vaadin会话。现在我正试图用原生JS和Ajax请求实现这一点,但我不知道如何在不每秒发出Ajax请求的情况下同步停止/启动和重置事件

这是计数器的Swing实现

公共无效计时器(){
计时器计时器=新计时器(1000,新ActionListener(){
已执行的公共无效操作(操作事件e){
如果(秒==0&&minutes>0){
分钟--;
秒=59;
}否则{
秒--;
}
label.setText(分钟+“:”+秒);
重新油漆();
}
});
timer.start();
}
现在,我将为JS代码提供一个SpringBootRESTAPI来请求剩余的几分钟和几秒钟

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

}

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

请从

/*
实时(可暂停)线性方程
值=_speed*Date.now()+_offset;
//暂停时,它只是:
值=_偏移量;
所以基本上是一个时钟,一个秒表,一个倒计时,一个仪表。。。
由于它只是一个随时间变化的线性方程,它与任何时间间隔无关。
它会在您要求时计算值(使用Date.now())。这是每帧还是每小时。
*/
上课钟{
构造函数(值=Date.now(),速度=1){
//状态;仅在设置其中一个属性(值、暂停或速度)时更改
这是._offset=+值| | 0;
这个。|速度=+速度| | 0;
这个。_暂停=真;
//准备一个简单的钩子,以便在状态更新后得到通知(可能是将新状态存储在localStorage中)
this.onStateChange=未定义;
}
获取值(){
返回此。_暂停?此。_偏移量:此。_速度*日期。现在()+此。_偏移量
}
设置值(arg){
设值=+arg | | 0;
让偏移量=这个。_暂停?值:值-这个。_速度*日期。现在();
如果(此偏移量!==偏移量){
这个。_offset=offset;
if(this.onStateChange==“函数”的类型)
本次变更(本次);
}
}
获取速度(){
把这个还给我
}
设定速度(arg){
设速度=+arg | | 0;
如果(此速度!==速度){
如果(!this.\u暂停)
this.\u offset+=Date.now()*(this.\u speed-speed);
这个。_速度=速度;
if(this.onStateChange==“函数”的类型)
本次变更(本次);
}
}
暂停{
将此返回。\u已暂停
}
设置暂停(arg){
让暂停=!!arg;
如果(此项已暂停!==暂停){
这个。_offset+=(暂停?1:-1)*这个。_speed*Date.now();
这个。_暂停=暂停;
if(this.onStateChange==“函数”的类型)
本次变更(本次);
}
}
时间(){
设value=this.value,v=Math.abs(value);
返回{
价值
//符号:值<0?-:“”,
秒:数学地板(v/1e3)%60,
会议记录:数学地板(v/6e4)%60,
时间:数学楼层(v/36e5)%24,
天数:数学楼层(v/864e5)
}
}
价值(){
返回此.value;
}   
开始(){
this.pause=false;
归还这个;
}
停止(){
this.paused=true;
归还这个;
}
}
我展示这一点是因为如果你仔细观察它,你会发现它的整个状态由两个数字和一个布尔值组成,它们只有在你做一些事情时才会改变,比如启动/停止它

根据该状态和计算机内部时钟计算实际值

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

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

/*
    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;
    }
}