如何让函数执行完毕后再调用?Electron JS场景遇问题
如何让逐字动画函数执行完毕后再调用下一个
我需要实现逐字打印的动画效果,但两个TypeAnimation函数会同时执行,导致输出字符混乱——原本要依次打印first line of text和next line of text but slower,结果输出成finrset xlitne olf itenxte of text but slower。
尝试过用Promise和async/await,但问题依旧,相关代码如下:
初始代码
function TypeAnimation(str, time) { var text = document.getElementById('loading'); for (let i = 0; i < str.length; i++) { let k = i; setTimeout(function(){ text.innerHTML += str.charAt(i); }, time * (k + 1)); } } function StartGame() { TypeAnimation('first line of text', 50) TypeAnimation('next line of text but slower', 100) } window.onload = StartGame;
尝试的Promise版本
function TypeAnimation(str, time) { return new Promise((resolve) => { var text = document.getElementById('loading'); for (let i = 0; i < str.length; i++) { let k = i; setTimeout(function(){ text.innerHTML += str.charAt(i); }, time * (k + 1)); } resolve(); }); } function StartGame() { TypeAnimation('first line of text', 50).then(TypeAnimation('next line of text but slower', 100)) } window.onload = StartGame;
尝试的async/await版本
async function StartGame() { await TypeAnimation('first line of text', 50) TypeAnimation('next line of text but slower', 100) }
问题根源
问题出在TypeAnimation的Promise实现里:resolve()是在for循环结束后立即执行的,根本没等所有setTimeout的回调执行完毕。这导致第一个函数的Promise马上变为resolved状态,第二个函数立刻启动,两个函数的定时器队列同时向DOM添加字符,最终造成输出混乱。
解决方案
要让Promise在所有字符打印完成后再resolve,有两种可靠的实现方式:
方案一:在最后一个字符的回调中触发resolve
修改TypeAnimation,在循环到最后一个字符时,执行完添加操作后调用resolve():
function TypeAnimation(str, time) { return new Promise((resolve) => { const text = document.getElementById('loading'); const totalChars = str.length; for (let i = 0; i < totalChars; i++) { setTimeout(() => { text.innerHTML += str.charAt(i); // 最后一个字符添加完成后resolve if (i === totalChars - 1) { resolve(); } }, time * (i + 1)); } }); } async function StartGame() { await TypeAnimation('first line of text', 50); // 添加换行让两行文本分开 document.getElementById('loading').innerHTML += '<br>'; await TypeAnimation('next line of text but slower', 100); } window.onload = StartGame;
方案二:计算总时长延迟resolve
如果不想在每个回调里做判断,也可以计算打印完所有字符的总时间,用额外的setTimeout延迟执行resolve():
function TypeAnimation(str, time) { return new Promise((resolve) => { const text = document.getElementById('loading'); for (let i = 0; i < str.length; i++) { setTimeout(() => { text.innerHTML += str.charAt(i); }, time * (i + 1)); } // 总时长 = 单字符间隔 * 字符总数,延迟后resolve setTimeout(resolve, time * str.length); }); } async function StartGame() { await TypeAnimation('first line of text', 50); document.getElementById('loading').innerHTML += '<br>'; await TypeAnimation('next line of text but slower', 100); } window.onload = StartGame;
修改后,第一个函数会完整打印完所有字符后,才会启动第二个函数,输出不会再混乱。添加<br>可以让两行文本分开显示,效果更清晰。
内容的提问来源于stack exchange,提问作者thejoshbaker
相关产品推荐
相关产品推荐

