这个问题确实让我想起了我对JS技能的看法...... :(
我觉得我是正确的,但是我很难理解概念的做法,这不是一个语法问题,因为我觉得我几乎破解了它。
我需要什么
我的当前代码(可以粘贴到控制台中)
var stringList = ['first test','second test'],
stringListLen = stringList.length;
for(var i = 0; i < stringListLen; i++){
// begin with first string and read it's length for iterations
var stringNumber = 0;
var currentString = stringList[stringNumber];
var currentStringLen = currentString.length;
// just see the word for clarification at this point in code
console.log(currentString);
(function (i) {
setTimeout(function () {
for (var j = 0; j < currentStringLen; j++) {
(function (j) {
setTimeout(function () {
// THE MAGIC HAPPENS HERE
console.log(j, currentString.charAt(j));
// End of string, so read next string, reset letter count
if(j === currentStringLen - 1){
stringNumber++;
currentString = stringList[stringNumber];
j = 0;
}
}, 300 * j); // each letter * specified delay
})(j);
};
}, currentStringLen * 300 * i); // letter * delay * letters in word
})(i);
}
问题
好的:我成功地获得了输出的字母之间的短暂延迟,并且当我们到达第一个单词的结尾时,我的检查切换到一个新单词并重置字母计数器...
坏了:我不能让两个词之间的等待工作。我已经尝试了一些想法,让自己感到困惑,我不知道我的方法现在是否正确。THE UGLY:上一个词的最后一个字母也没有输出,这完全出乎意料。
我尝试了什么。
好吧,我尝试过简单地将“currentStringLen * 300 * i”元素更改为看似合乎逻辑但效果更好或更差的各种组合。最终我想我正在尝试计算“等待当前字符串中的字母数300(字母延迟)*”&lt; ---- STRIKETHROUGH ...
我实际上不知道我在计算什么,这就是问题。
我现在认为我想把它分成两个函数,而不是两个嵌套函数。一个字符串READ AND PASS到另一个JUST输出短暂延迟字母的函数,然后一旦到达最后一个字母,它就会调用第一个函数询问下一个字。但是,我仍然需要递归数组中产生同样问题的字符串数量......
我在这里错过了什么基本的人吗?
答案 0 :(得分:1)
这大致是你想到的吗?
function printLetters(stringList) {
var wordIndex = 0,
letterIndex = 0;
printNext();
function printNext() {
var word = stringList[wordIndex];
var letter = word.charAt(letterIndex);
console.log(letter);
++letterIndex;
if (letterIndex === word.length) {
letterIndex = 0;
++wordIndex;
if (wordIndex < stringList.length) {
setTimeout(printNext, 2000);
}
return;
}
setTimeout(printNext, 300);
}
}
printLetters(['first test', 'second test']);
此处只有一个setTimeout
同时运行,并且根据需要在适当的时间设置新的。{/ p>
虽然我不建议同时运行多个计时器,但可以完成。像这样:
function printLetters(stringList) {
var letterCount = 0,
startTime = Date.now();
stringList.forEach(function(word, wordCount) {
word.split('').forEach(function(letter) {
setTimeout(function() {
console.log(letter, Date.now() - startTime);
}, wordCount * 1700 + (letterCount * 300));
++letterCount;
});
});
}
printLetters(['first test', 'second test']);
这里我已经在日志记录中包含了时间增量,以便更好地了解何时发生的事情。字符串之间的差距是2000,但代码中的常量是1700,因为已经添加了300个。
答案 1 :(得分:1)
我会做一个完全不同的方法。我不会做一堆预先计算的超时及其关联的闭包,而是一次只执行一次超时,使用递归然后继续下一次超时:
function delayShow(words) {
if (!words || words.length === 0) {
return;
} else if (words[0].length === 0) {
words.shift()
setTimeout(() => delayShow(words), 2000);
} else {
console.log(words[0].charAt(0));
words[0] = words[0].substr(1);
setTimeout(() => delayShow(words), 300);
}
}
delayShow(['first test','second test']);
答案 2 :(得分:0)
你可以在循环中使用一个条件,当你在字符串字符的最后一次迭代时,你会在超时内再次调用递归函数来迭代数组中的下一个字符串等。
var stringList = ['first test', 'second test'];
(function rec(j) {
var chars = stringList[j].split('');
chars.forEach(function(char, i) {
setTimeout(function() {
console.log(char);
// if it's the last iteration && there are more strings in the array
if ((i == (chars.length - 1)) && (j < stringList.length - 1)) {
setTimeout( function() {
rec(++j); // play it again
}, 2000);
}
}, i * 300);
});
})(0);
&#13;
答案 3 :(得分:0)
即使像setTimeout这样微不足道的东西,也是使用async / await的一个很好的例子。所以我在下面列举了一个例子。
正如您将看到的,代码更容易理解。具有不创建多个同时运行的setTimeout的附加优点。
它还有助于使事情变得更容易,例如。如果我要求你改变下面的代码,以便SPACE花费的时间少于其他字母,为了让它更自然地流动,它不会花很多心思去研究改变什么。
var
stringList = ['first test','second test'];
async function delay(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
}
async function run() {
let wordpos = 0;
let wordElem = document.querySelector('.words');
while (true) {
let word = stringList[wordpos];
let text = '';
for (var letterpos = 0; letterpos < word.length; letterpos ++ ) {
let letter = word[letterpos];
text = text + letter;
wordElem.innerText = text;
await delay(300);
}
await delay(2000);
wordpos = (wordpos + 1) % stringList.length;
}
}
run();
&#13;
<h1 class="words">?</h1>
&#13;