1. 执行方式
schedule 是 Cocos Creator 提供的一种调度方法,通常用于在每帧或者定时器周期内定期调用一个方法。你可以指定一个函数每隔一定的时间间隔执行一次。
setTimeout 用于 延迟执行一次 回调函数。指定一个延迟时间(毫秒)后,回调函数将会执行一次。
setInterval 会按照 固定时间间隔 重复执行回调函数,直到被手动清除。
2.基于帧更新 vs 基于事件循环
schedule是基于 Cocos Creator 的游戏主循环的,调度任务会按照 帧更新 的节奏,特别是如果你选择每帧执行的话。
//如果你传递 0 作为时间间隔,schedule 将会在每帧执行(例如每秒 60 帧),它会执行 60 次。帧率较低时(例如每秒 30 帧),它的执行频率也会降低。
this.schedule(function() {
console.log('每帧执行');
}, 0); // 0表示每帧调用一次
// 每隔1秒执行一次
this.schedule(function() {
console.log('每1秒执行一次');
}, 1); // 1秒调用一次
setTimeout 和 setInterval都是基于 JavaScript 的 事件循环 的。它们依赖于浏览器的定时器机制,不与游戏帧更新有关,因此不会受到游戏的帧率波动影响。
setTimeout(function() {
console.log('延迟1秒执行');
}, 1000); // 1000毫秒(1秒)后执行
// 每隔1秒执行一次
const intervalId = setInterval(function() {
console.log('每秒执行一次');
}, 1000); // 每隔1秒执行一次
// 如果想停止这个定时器
clearInterval(intervalId);
3 取消机制
schedule 在 Cocos Creator 中是通过 unschedule 或 unscheduleAllCallbacks 来取消的。
setTimeout 会返回一个定时器 ID,你可以通过 clearTimeout(id) 来取消已设置的定时任务。
setInterval 会返回一个定时器 ID,你可以通过 clearInterval(id) 来停止它的定期执行。
4.使用过程中需注意-防止内存泄漏
在 Cocos Creator 中使用 schedule 和 setTimeout、setInterval 时,如果没有适当的清理和管理,可能会导致 内存泄漏。这主要是因为这些定时器(或调度器)可能会继续保持对某些对象的引用,导致垃圾回收机制无法释放这些对象。为了避免内存泄漏,你需要确保定时器或调度任务在不需要时被正确地清理。
schedule
在 Cocos Creator 中,使用 schedule 通常 不会直接导致内存泄漏,当一个节点被销毁时(例如,调用了 destroy()),或者该节点进入了 禁用状态(例如,调用了 node.active = false),Cocos Creator 会自动调用 unscheduleAllCallbacks 来清除该节点上的所有调度任务。
setTimeout 和 setInterval 在执行回调时,回调函数通常会捕获其周围作用域的变量。如果回调中引用了组件实例、节点或其他大型对象,JavaScript 会保持这些对象的引用,直到定时器被清除。这意味着即使这些对象不再需要,它们也无法被垃圾回收。
cc.Class({
extends: cc.Component,
onLoad() {
// 使用 setTimeout 延迟执行回调
setTimeout(() => {
// 回调函数中引用了 this,this 仍然会被保留,直到定时器被清除
console.log(this.node.name);
}, 1000);
},
onDestroy() {
// 这里没有清除定时器
}
});
完整的内存清理代码
cc.Class({
extends: cc.Component,
onLoad() {
this.schedule(this.updateTask, 1); // 每1秒执行一次
this.timeoutId = setTimeout(this.delayedTask, 2000); // 延迟2秒执行
this.intervalId = setInterval(this.repeatedTask, 1000); // 每秒执行一次
},
updateTask() {
console.log('1秒间隔任务');
},
delayedTask() {
console.log('延迟2秒任务');
},
repeatedTask() {
console.log('每秒重复任务');
},
onDestroy() {
this.unschedule(this.updateTask); // 清除调度任务
clearTimeout(this.timeoutId); // 清除 setTimeout
clearInterval(this.intervalId); // 清除 setInterval
}
});
避免长时间引用组件:尽量避免定时器回调中引用组件或大对象,尤其是当这些对象不再需要时。可以使用箭头函数或 bind 来确保 this 指向正确,但要小心避免在回调中持续引用组件。
使用 onDisable 或 onDestroy 进行清理:当你知道不再需要某个定时器或调度任务时,及时清除它们。