如何判断setInterval 是否正在执行?
@manji setInterval
和 setTimeout
返回的都是 Number
,都是相应的 ID。
不过楼主需要的是判断 setInterval
是否在执行……
其实这个比较好的办法还是在执行函数里加一些处理 ,比如加一个计数器之类的,通过这个变量的变化了能了解它是否还在执行。比如
(function(ifun) {
ifun.exeCount = 0
setInterval(function() {
ifun()
ifun.exeCount++
}, 1000)
})(intervalFunction)
补充:2022-10-2
既然 @OceanZH 提到“优雅”,那就来实现一个优雅一点的。setInterval() 没有提供管理的机制,所以要从 setInterval() 返回的 id 来判断是否运行就比较困难。不过,如果对原生 interval 进行一层封装,把这个过程管理起来,就容易了。
下面的代码写了一个 ManagedInterval 类来管理,并使用 startInterval()
来开启(当然也可以实现一个 stopInterval()
来结束,只是这里没写)
class ManagedInterval {
#fn;
#interval;
#timer;
constructor(fn, interval) {
this.#fn = fn;
this.#interval = interval;
}
get active() { return !!this.#timer; }
start() {
if (this.#timer) { return; }
this.#timer = setInterval(this.#fn, this.#interval);
}
stop() {
clearInterval(this.#timer);
this.#timer = undefined;
}
}
function startInterval(fn, interval) {
var mi = new ManagedInterval(fn, interval);
mi.start();
return mi;
}
// 试验:每 500 毫秒输出当时时间
var timer = startInterval(
() => console.log(new Date()),
500,
);
// 1200 毫秒后检查 interval 的活动状态 (true)
setTimeout(
() => console.log("is active: ", timer.active),
1200
);
// 2400 毫秒后停止 interval
setTimeout(
() => timer.stop(),
2400,
);
// 3000 毫秒后再次检查 interval 的活动状态 (false)
setTimeout(
() => console.log("is active (stopped): ", timer.active),
3000,
);
@边城
我重写了个管理类。注意stop的返回值
// interval 管理类
class ManagedInterval {
//维护一个intervalId和对应活动状态的字典
static dir = {}
static active(id) {
if (id in this.dir) {
return this.dir[id]
}
}
static start(fn, interval) {
timer = setInterval(fn, interval)
this.dir[timer] = true
return timer
}
//返回值表示当前状态是否已经被打断
static stop(id, flag = false) {
let active = this.active(id)
if (active) {
clearInterval(id)
this.dir[id] = false
}
if (flag) {
this.remove(id)
}
return active
}
//在合适的时刻清理字典
static remove(id) {
if (id in this.dir) {
delete this.dir[id]
}
}
}
根据题主的问题,以及我自己遇到的问题,遇到的需求可能是这样的:我们希望当前只有一个协程在执行,当协程结束后执行一个回调callback
,比如维护一个timer
表示当前唯一活动的协程的intervalId
,timer
的状态有自然结束的,这时候应该执行callback
,和被掐断的,即另一个协程开启,当前timer
应该先掐断再执行另一个协程。
这时候就会有一个问题,需要通过timer
是否活动来判断callback
是否应该去执行(不活动就说明被其它协程掐断了)。使用我上面的管理类来简单演示一下。
//维护一个全局变量,表示当前唯一活动的协程
let timer
//逻辑定义在方法里
const fade = async (funcTODO, duraton, slerp) => {
// 判空,确保只有一个协程存在
ManagedInterval.stop(timer)
timer = ManagedInterval.start(funcTODO, duraton / slerp)
// 被打断时timer值会变化,故需保存当前的timer信息
let tmpTimer = timer
//休眠
await sleep(duraton)
// 分两种情况:
// 1.正常结束,返回true,执行callback
// 2.被打断,返回false,不执行callback
res = ManagedInterval.stop(tmpTimer, true)
if (res) {
//callBack
}
}
我试着实现了,现在它正在为我的另一个“玩具”做出贡献。@边城
class Eventable {
static eventMap = {}
// 务必确保没有重名的方法
static on(type, handler) {
type = type.toLowerCase()
;(this.eventMap[type] || (this.eventMap[type] = [])).push(handler)
}
static off(cfg) {
if (cfg?.type && cfg?.handler) {
let new_set = new Set(this.eventMap[cfg.type.toLowerCase()])
if (new_set.has(cfg.handler)) {
// console.log('方法删除成功')
new_set.delete(cfg.handler)
this.eventMap = [...new_set]
}
} else if (cfg?.type) {
delete this.eventMap[cfg.type.toLowerCase()]
// console.log('任务删除成功')
} else {
this.eventMap = {}
// console.log('全部删除成功')
}
}
static trigger(type) {
this.eventMap[type.toLowerCase()]?.forEach(handler => {
handler()
})
}
}
这里有一些manager和一个消息中心,我在消息中心把它们进行组合
class Eventable {
//不会ts,随便看看
// {type->sting : handler->arr}
static eventMap = {}
// {type->string : handler->{any : args->arr}}
static argsMap = {}
// 务必确保没有重名的方法
static on(type, handler, ...args) {
type = type.toLowerCase()
;(this.eventMap[type] || (this.eventMap[type] = [])).push(handler)
;(this.argsMap[type] || (this.argsMap[type] = {}))[handler] = args
}
static off(cfg) {
if (cfg?.type && cfg?.handler) {
//event
let new_set = new Set(this.eventMap[cfg.type.toLowerCase()])
if (new_set.has(cfg.handler)) {
new_set.delete(cfg.handler)
this.eventMap = [...new_set]
}
//args
delete this.argsMap[cfg.type.toLowerCase()][cfg.handler]
// console.log('方法删除成功')
} else if (cfg?.type) {
//event
delete this.eventMap[cfg.type.toLowerCase()]
//args
delete this.argsMap[cfg.type.toLowerCase()]
// console.log('任务删除成功')
} else {
//event
this.eventMap = {}
//args
this.argsMap = {}
// console.log('全部删除成功')
}
}
static trigger(type) {
this.eventMap[type.toLowerCase()]?.forEach(handler => {
handler(...this.argsMap[type.toLowerCase()][handler])
})
}
}
现在可以提供参数了!(:
经测试,var timer=window.setInterval(...),console.log(timer)是1,typeof timer的结果是number,我估计它是计时器的id,于是我做了个实验:
var i = 0;
var k = window.setInterval(function(){
i++;
console.log(i);
if(i>10){
window.clearInterval(1); // 注意这里,不是k是1
// window.clearInterval(k); // 跟上一句效果一样
}
},10);
上面的代码只输出到11,说明这真是个计时器的id,我试图在window对象里面找到那个能获取装这些id的容器的方法,但没找到。
8 回答4.7k 阅读✓ 已解决
6 回答3.4k 阅读✓ 已解决
5 回答2.8k 阅读✓ 已解决
5 回答6.3k 阅读✓ 已解决
4 回答2.3k 阅读✓ 已解决
4 回答2.8k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决