如何在JavaScript动画循环中仅执行一次函数?
在动画循环中仅执行一次函数的最佳实践
问题场景
你有一段基于requestAnimationFrame的动画循环代码,当前sayHello函数会在每帧动画中重复执行:
function sayHello () { console.log('hello') // 修正原代码拼写错误:consile → console } function animate () { sayHello(); window.requestAnimationFrame(animate); } animate();
你希望让sayHello仅执行一次,自己尝试了全局标志变量的方案,但觉得这种写法繁琐且可读性差:
let saidHello = false; function animate () { if(saidHello === false) { sayHello(); saidHello = true; } window.requestAnimationFrame(animate); }
以下是几种更优雅的最佳实践方案:
方案1:闭包封装标志变量
把标志变量封装在闭包内,避免污染全局作用域,同时让逻辑更紧凑:
function sayHello () { console.log('hello'); } // 立即执行函数创建闭包,保存执行状态 const animate = (() => { let hasRun = false; return function () { if (!hasRun) { sayHello(); hasRun = true; } window.requestAnimationFrame(animate); }; })(); animate();
方案2:封装通用的一次性执行函数
写一个可复用的once工具函数,能把任意函数转换成仅执行一次的版本,复用性强且代码可读性高:
// 通用工具函数:让目标函数仅执行一次 function once(fn) { let called = false; return function (...args) { if (!called) { called = true; return fn.apply(this, args); } }; } function sayHello () { console.log('hello'); } // 生成仅执行一次的sayHello const sayHelloOnce = once(sayHello); function animate () { sayHelloOnce(); // 无论调用多少次,只会执行一次 window.requestAnimationFrame(animate); } animate();
方案3:启动动画前直接执行(最简方案)
如果sayHello不需要严格在第一次动画回调内执行,直接在启动动画前调用一次即可,这是最简洁的写法:
function sayHello () { console.log('hello'); } function animate () { window.requestAnimationFrame(animate); } // 启动动画前先执行一次 sayHello(); animate();
方案4:用AbortController灵活控制
如果需要更灵活的控制(比如中途决定取消执行),可以使用AbortController来终止后续的执行逻辑:
function sayHello () { console.log('hello'); } const controller = new AbortController(); const { signal } = controller; function animate () { if (!signal.aborted) { sayHello(); controller.abort(); // 执行后立即标记为终止,后续不再执行 } window.requestAnimationFrame(animate); } animate();
内容的提问来源于stack exchange,提问作者Brixsta
相关产品推荐
相关产品推荐

