Imbricated循环+超时有时会失败

时间:2017-03-12 17:15:17

标签: javascript jquery loops timeout

我做了一个小脚本练习,似乎我的循环和他们的超时有问题。 这是我的脚本的链接:http://codepen.io/JulienBarreira/pen/EWNoxJ

有时,当一个单词写作时,一两个字母就错了。例如,我没有“芝士汉堡”,而是“chkesebxrger”。

我发现了一个小技巧,所以它失败了,但我根本不知道为什么。

  function charsAnim(i, word, j) {
    setTimeout(function() {
      var count = j; 
      if (j < steps) {           
        randomChar(i, word, count, j);
      } else {
        goodChar(i, word, count, j);
      }
      /* seems it fails less if I divide j, don't know why */
    }, (speed/steps)*(j / 1.8));
  }

当其他脚本在计算机上运行时(例如在我的个人资料页面中),问题会更频繁地出现。

即使不是我的问题,也请随时向我提供有关我的代码的任何建议。可能有一种更简单的方法来做同样的事情,我在这里进步。

谢谢:)

编辑:我在一个代码段中添加了3个iframe来向您显示问题,当您启动代码段时,第一个单词大部分时间都会失败。

var words = [
  'unicorn',
  'cheeseburger',
  'pizza',
  'pineapple',
  'popsicle',
  'bubbles',
  'seagull',
  'doodle',
  'goggles',
  'artichoke',
  'potato',
  'carrot',
  'vegeta'
];
var letters = "abcdefghijklmnopqrstuvwxyz#%&^+=-";
var speed = 250;
var steps = 4;

function getRandomWord() {
  var randomWord = words[Math.floor(Math.random() * words.length)];
  return randomWord;
}
function getRandomLetter() {
  var randomLetter = letters[Math.floor(Math.random() * letters.length)];
  return randomLetter;
}

function randomWordLoop() {
  var word = getRandomWord();
  var textLength = word.length;
  for(i = 0; i < textLength; i++) {    
    letterAppear(i, word);
  }  
  
  function letterAppear(i, word) {
    setTimeout(function() {
      randomLetters(i, word);    
    }, speed*i);  
  }

  function randomLetters(i, word) {
    for (j = 0; j <= steps; j++) {
      charsAnim(i, word, j);
    }
  }

  function charsAnim(i, word, j) {
    setTimeout(function() {
      var count = j; 
      if (j < steps) {           
        randomChar(i, word, count, j);
      } else {
        goodChar(i, word, count, j);
      }
      /* seems it fails less if I divide j, don't know why */
    }, (speed/steps)*(j / 1.8));
  }

  function randomChar(i, word, count, j) {
    var letter = getRandomLetter();
    if (j > 0) {
      var oldText = $('#loader').text().slice(0, -1);
    } else {
      var oldText = $('#loader').text();
    }
    $('#loader').text(oldText + letter);    
  }
  function goodChar(i, word, count, j) {
    var oldText = $('#loader').text().slice(0, -1);  
    $('#loader').text(oldText + word[i]);
    if (i == textLength - 1 ) {
      removeWord();
    }
  }
  
  function removeWord() {
    setTimeout(function() {
      for (k = 0; k < textLength; k++) {
        removeLetters(k);
      }
    }, speed*2);
  }
  function removeLetters(k) {
    setTimeout(function() {
      removeLetter(k);
    }, 75*k);
  }
  function removeLetter(k) {
    var actualText = $('#loader').text().slice(0, -1);
    $('#loader').text(actualText);
    if (k == textLength - 1) {
      randomWordLoop();
    }
  }
}

randomWordLoop();
body {
  background-color: #010101;
}
.loader {
  width: 300px;
  color: #0c9c73;
  text-align: left;
  font-size: 50px;
  font-family: Roboto Mono;
  font-weight: 700;
  text-transform: uppercase;
}
.loader:after {
    content:'_';
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700" rel="stylesheet">
<div class="loader" id="loader"></div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GquEnoqZAK0?autoplay=1" frameborder="0" allowfullscreen></iframe>

1 个答案:

答案 0 :(得分:1)

您正在randomWordLoop()

内合并此循环
for(i = 0; i < textLength; i++) {    
  letterAppear(i, word);
}

... setTimeout()位于letterAppear()内。基本上,当letterAppear()letterAppear内执行时,i变量不再具有与设置超时时相同的值。它具有全局值,可能已被页面中可能使用i的任何其他函数设置为完全不同的值。

另请注意,设置for的正确方法不是全局使用i,而是将其设置为函数的局部变量:for(var i = 0; i < textLength; i++) {...}

你无法正确看到它,因为你的函数会输出随机字母,并且没有任何视觉线索让你知道它运行在i的错误值上,但我相信你的功能在大多数情况下是错误的。

要解决此问题,您需要letterAppear()中的一个闭包,它会将iword的正确值传递给setTimeout()内的randomLetters(),无论如何setTimeout()的内容执行时的全局值:

for(var i = 0; i < textLength; i++) {    
  (function(i,word){
    letterAppear(i, word);
  })(i,word)
}  

仔细观察代码,您可能需要在多个位置进行闭包(如果在代码执行时传递给函数的值非常重要),您还应该定义for迭代器( ij}在本地,使用var,就像我上面所做的那样。

永远不要忘记你最好的JavaScript朋友:

console.log(this, arguments);