簡體   English   中英

如何停止JavaScript中的異步功能?

[英]How to stop asynchronous function in JavaScript?

我有一些異步問題。 我正在處理ECMAScript 6對象。 這是一個計時器,我希望能夠在其倒計時期間重新啟動。

這是我的工作:

export class Timer {
    constructor(sec){
        this.sec = sec;
        this.count = sec;
        this.running = false;
    }

    start() {
        this.running = true;
        this._run();
    }

    _run(){
        if(this.running){
            setTimeout(()=>{
                this.count --;
                console.log(this.count);
                if(this.count<0){
                    this.running = false;
                }
                this._run();
            }, 1000);
        }
    }

    restart(){
        this.running = false;
        /*
            Wait until _run() is done then :
        */
        this.count = this.sec;
        this.start();
    }
}

restart()函數中,如何知道_run()何時停止運行?

知道計時器是否“正在運行”的一種更簡單的方法是使用setInterval代替。

var interval = setInterval(() => updateTimer(), 10); // update every 10ms

如果設置了interval它正在運行

if (interval) // timer is running

停止計時器

window.clearInterval(interval);
interval = null;
// timer is no longer "running"

補充筆記

注意創建以固定值遞增的計時器

在您的代碼中,您有

setTimeout(() => this.count--, 1000);

目的是讓您每秒減少一次count屬性,但這不是您可以保證的行為。

看看這個小腳本

var state = {now: Date.now()};

function delta(now) {
  let delta = now - state.now;
  state.now = now;
  return delta;
}

setInterval(() => console.log(delta(Date.now())), 1000);

// Output
1002
1000
1004
1002
1002
1001
1002
1000

我們使用了setInterval(fn, 1000)但實際間隔每次都會變化幾毫秒。

如果您執行諸如將瀏覽器的焦點切換到其他選項卡,打開新的選項卡等操作,則會誇大問題。查看這些更零星的數字

1005 // close to 1000 ms
1005 // ...
1004 // a little variance here
1004 // ...
1834 // switched focus to previous browser tab
1231 // let timer tab run in background for a couple seconds
1082 // ...
1330 // ...
1240 // ...
2014 // switched back to timer tab
1044 // switched to previous tab
2461 // rapidly switched to many tabs below
1998 // ...
2000 // look at these numbers...
1992 // not even close to the 1000 ms that we set for the interval
2021 // ...
1989 // switched back to this tab
1040 // ...
1003 // numbers appear to stabilize while this tab is in focus
1004 // ...
1005 // ...

因此,這意味着您不能依賴setTimeout (或setInterval )函數每1000毫秒運行一次。 count會因各種因素而有很大的減少。

要解決此問題,您需要使用增量。 這意味着在每次“滴答”計時器之前,您都需要使用Date.now進行時間戳記。 在下一個刻度上,采用新的時間戳,並從新的時間戳中減去以前的時間戳。 那是你的delta 使用此值,將其添加到計時器的總ms數中,以獲取計時器已運行的精確毫秒數。

然后,所有對時間敏感的值將是總累積ms的投影/計算。

在您的情況下,假設您的count10開始。 如果要每1000毫秒遞減-1 ,可以執行

function update() {
  // update totalMs
  this.totalMs += calculateDelta();
  // display count based on totalMS
  console.log("count %d", Math.ceil(this.count - this.totalMs/1000));
}

這是一個示例ES6計時器,它實現了delta功能,可能對您有幫助

class Timer {
  constructor(resolution=1000, ms=0) {
    this.ms = ms
    this.resolution = resolution;
    this.interval = null;
  }
  delta(now) {
    let delta = now - this.now;
    this.now = now;
    return delta;
  }
  start() {
    this.now = Date.now();
    this.interval = window.setInterval(() => this.update(), this.resolution);
  }
  reset() {
    this.update();
    this.ms = 0;
  }
  stop() {
    this.update();
    window.clearInterval(this.interval);
    this.interval = null;
  }
  update() {
    this.ms += this.delta(Date.now());
    console.log("%d ms - %0.2f sec", this.ms, this.ms/1000);
  }
}

創建一個具有50毫秒“分辨率”的新計時器。 這意味着計時器顯示每50 ms更新一次。 您可以將此值設置為任何值,計時器仍將保持准確的值。

var t = new Timer(50);
t.start();

為了模擬重置,我們可以創建一個一次性超時,以便您可以看到重置工作正常

// in ~5 seconds, reset the timer once
setTimeout(() => t.reset(), 5000);

這是暫停計時器的演示

// in ~10 seconds, pause the timer
setTimeout(() => t.stop(), 10000);

您也可以恢復計時器

// in ~12 seconds, resume the timer (without reset)
setTimeout(() => t.start(), 12000);

您可以隨意startstopreset計時器


這是轉譯為ES5的ES6(如上所述),因此您可以看到代碼在可運行的代碼段中運行。 打開控制台,然后單擊“運行代碼段”

 "use strict"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Timer = (function () { function Timer() { var resolution = arguments.length <= 0 || arguments[0] === undefined ? 1000 : arguments[0]; var ms = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1]; _classCallCheck(this, Timer); this.ms = ms; this.resolution = resolution; this.interval = null; } Timer.prototype.delta = function delta(now) { var delta = now - this.now; this.now = now; return delta; }; Timer.prototype.start = function start() { var _this = this; this.now = Date.now(); this.interval = window.setInterval(function () { return _this.update(); }, this.resolution); }; Timer.prototype.reset = function reset() { this.update(); this.ms = 0; }; Timer.prototype.stop = function stop() { this.update(); window.clearInterval(this.interval); this.interval = null; }; Timer.prototype.update = function update() { this.ms += this.delta(Date.now()); console.log("%d ms - %0.2f sec", this.ms, this.ms / 1000); }; return Timer; })(); var t = new Timer(50); t.start(); // in ~5 seconds, reset the timer once setTimeout(function () { return t.reset(); }, 5000); // in ~10 seconds, pause the timer setTimeout(function () { return t.stop(); }, 10000); // in ~12 seconds, resume the timer (without reset) setTimeout(function () { return t.start(); }, 12000); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM