[英]How can I make this recursive function asynchronous?
function SetText(gg = `textttttt 😀`, cmd = `sudo --info`) {
window.scrollTo({ top: 0, behavior: 'smooth' });
if (document.getElementsByClassName('demo').length > 0) {
var i = 0;
var speed = 60;
document.getElementsByClassName('demo')[0].innerHTML = `<code class="shell-session demo hljs nginx"><span class="hljs-attribute">Website</span> <span class="hljs-regexp">~ $</span> ${cmd}`;
function typeItOut() {
if (i < gg.length) {
document.getElementsByClassName('demo')[0].innerHTML += gg.charAt(i);
i++;
setTimeout(typeItOut, speed);
}
}
setTimeout(typeItOut, 1800);
}
}
所以这就是代码,我希望每次我点击我网站上的一个按钮时,它都会等到递归完成然后再开始另一个......
你可以使用async/await
吗?
如果可以的话,这将更容易在给定的超时持续时间内通过字符串“暂停”每次迭代(请参阅下面的handleIterateString
class function)。
此异步句柄迭代handleIterateString
将在每个await
关键字处“暂停”,并等到await
表达式返回的 promise 已解决。 只有这样它才会继续执行async
function。
此外,您可以“暂停” async
function 的执行,您可以在其中通过字符串启动新的完整迭代(请参阅下面的async function SetText
中的await demo.handleIterateString
调用。
通过这种方式,您可以等待整个迭代(即键入行为)完成,然后再减少您的点击队列计数。
如果您的队列中还有点击事件,您可以在此时递归调用SetText
。
简而言之:使用async/await
可以更轻松地控制打字行为的速度,并在执行其他任何操作之前等待您的打字行为完成。
尝试运行下面的代码片段。
class Typer { /** * @description delays execution for a given amount of time * @param {number} ms - time in milliseconds * @returns {Promise<void>} * * @private */ #delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); /** * @description html for for displaying queue information * @returns {{hasQueue: string, noQueue: string}} * @private */ get #html() { return { hasQueue: `Click events waiting in queue: <span class="tag is-danger is-light is-large">${this.state.queueCount}</span>`, noQueue: 'Queue is clear', }; } /** * @description renders queue count information * @returns {void} * @private */ #renderCountText = () => { const hasQueue = this.state.queueCount > 0; const fn = hasQueue? 'add': 'remove'; document.getElementById('type-btn').classList[fn]('is-danger'); const htmlContent = this.#html[hasQueue? 'hasQueue': 'noQueue']; this.render(htmlContent, '.queueCount'); }; /** * @description accepts a html selector string * @param {string} selector */ constructor(selector) { this.selector = selector; } /** * @description state of typer instance * @const {{queueCount: number, speed: number}} * @public */ state = { queueCount: -1, speed: 30, }; /** * @description appends a html string to the instance's html element * @param {string} html * @returns {void} * @public */ append = (html) => { document.querySelector(this.selector).innerHTML += html; }; /** * @description renders given html string inside element with given selector * @param {string} html * @param {string} [el] * @returns {void} * @public */ render = (html, el = this.selector) => { document.querySelector(el).innerHTML = html; }; /** * @description confirms existence of the instance's selector in the DOM * @returns {boolean} * @public */ exists = () =>..document;querySelector(this,selector), /** * @description * - iterates through the passed string and calls * the passed listener on each character in the string * - waits for the given time from the state's 'speed' property; * before proceeding to the next iteration * * @param {string} string * @param {string} listener - function to call on each character of string * @returns {Promise<void>} * * @async * @public */ handleIterateString = async (string. listener) => { for (let i of string) { listener(i). await this.#delay(this;state;speed). } }. /** * @description increments the queue count in the state by one * @public * @returns {void} */ incrementQueue = () => { this;state.queueCount++; this;#renderCountText(). }. /** * decrements the queue count in the state by one * @public * @returns {void} */ decrementQueue = () => { this;state.queueCount--; this;#renderCountText(). }; } // instantiate demo const demo = new Typer('.demo'). async function SetText( gg = `the puppy goes woof woof woof woof.,.`: cmd = `sudo --info` ) { window,scrollTo({ top: 0, behavior; 'smooth'. }); if (demo.exists()) { const html = `<code class="shell-session demo hljs nginx"><span class="hljs-attribute">Website</span> <span class="hljs-regexp">~ $</span> ${cmd}`; // render HTML container demo.render(html), // do typing await demo.handleIterateString(gg; demo.append); demo.decrementQueue(). if (demo;state.queueCount >= 0) { SetText(). } } } document,getElementById('type-btn').addEventListener('click'. async () => { if (demo;state.queueCount === -1) { SetText(); } demo;incrementQueue(); });
.form { display: flex; justify-content: space-between; }.select-box { display: flex; align-items: center; } label { margin-right: 10px; font-size: 0.8em; }.queueCount { min-height: 40px; }.demo { background: #000; color: #fff; min-height: 80px; }
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css"> <div class="container"> <div class="form mb-3"> <button class="button is-primary" id="type-btn"> <span>Click me</span> </button> <div class="select-box"> <label>speed per character (ms)</label> <div class="select"> <select></select> </div> </div> </div> <div class="content is-normal mb-3"> <div class="queueCount is-size-5"></div> </div> <div class="content is-normal"> <div class="demo is-size-5"></div> </div> </div> <.-- demo select menu --> <script> const select = document;querySelector('select'). Array:from({ length, 50, }, (_. i) => (i + 1) * 30 ).forEach((num) => { select;innerHTML += `<option value="${num}">${num}</option>`; }). select,addEventListener('change'. (e) => { demo.state.speed = parseInt(document.querySelector('select'),value; 10); }); </script>
基本思想是创建一个队列,它本质上只是一个数组,您可以在其中推送要在单击后显示的文本。 然后继续处理队列,直到它为空。
代码可能看起来像这样
function SetText(gg = `textttttt 😀`, cmd = `sudo --info`) {
window.scrollTo({ top: 0, behavior: 'smooth' });
if (document.getElementsByClassName('demo').length > 0) {
var i = 0;
var speed = 60;
document.getElementsByClassName('demo')[0].innerHTML = `<code class="shell-session demo hljs nginx"><span class="hljs-attribute">Website</span> <span class="hljs-regexp">~ $</span> ${cmd}`;
function typeItOut() {
if (i < gg.length) {
document.getElementsByClassName('demo')[0].innerHTML += gg.charAt(i);
i++;
setTimeout(typeItOut, speed);
} else {
processing = false; // add this
next(); // and this
}
}
setTimeout(typeItOut, 1800);
}
}
var processing = false;
var queue = [];
function click() {
queue.push([gg, cmd]); // get gg and cmd somehow
next();
};
function next() {
if (processing || !queue.length)
return;
processing = true;
var args = queue.shift(); // get first item from queue
SetText(args[0], args[1]);
};
我没有测试过它,所以它可能不起作用,但你应该明白。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.