[英]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的投影/計算。
在您的情況下,假設您的count
從10
開始。 如果要每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);
您可以隨意start
, stop
, reset
計時器
這是轉譯為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.