与setTimeout

时间:2018-06-21 02:45:46

标签: javascript settimeout

所以我的问题是超时, 因为到它开始时,我的数组被重置,所有其他值也被更改。

我在message数组中输入了用户输入的内容,这是他们输入的行。 例如:

messages = ["first line", "second", "third", "etc.."];

for(var i=0; i < messages.length; i++){
    setTimeout(function () {
        draw(messages[i], x, y+(i*k*f) );
    }, i*20*messages[i].length);
}
message = "";
messages = [];

kf分别是常数值32,但是用户可以将其更改为任何浮点值。 xy是一些坐标。

因此,一旦调用draw()函数,则值是不确定的或错误的。

我已经搜索了一些答案,但是没有一个答案足以让我弄清楚我需要为特定案例做些什么。

5 个答案:

答案 0 :(得分:7)

您的for循环根据示例messages的长度执行4次。但是,当第一个setTimeout结束并触发其中的匿名函数时,messages数组在后面的代码行中已经为空。

在最后一行代码中,您将messages数组重新初始化为空数组,并且在异步setTimeout回调发生时,它们正在尝试访问索引0,1, 2,3不再存在,因此结果是未定义的值。

messages = []; // an empty array with zero length

为帮助弄清正在发生的事情,请考虑以下问题:

// this is what you might expect
var arr = [ "foo", "bar", "baz"];
console.log(arr[0]); // logs "foo" to the console

// this is actually what's happening
var arr = []; // set arr equal to a new empty array
console.log(arr[0]); // logs "undefined" to the console

我只解释了原因和原因。 @brk在回答中提供了两种代码解决方案。

答案 1 :(得分:2)

在Javascript setTimeout中,函数是异步的。所以您的以下代码

messages = [];

它在实际超时回调函数被调用之前执行,您会看到错误,因为在实际回调函数被调用时messages变量为空。

尝试了解有关异步Java脚本的更多信息,您会更好地理解。

答案 2 :(得分:2)

创建一个闭包和一个立即调用的函数表达式,并在settimeout回调函数内部传递变量以对其进行访问

Integer.to_string(43981, 16) # "ABCD"

Integer.to_string(43981, 2) # "1010101111001101" Integer.to_string(43981, 8) # "125715" 关键字的替代用法。用let关键字声明的变量在当前块中始终具有作用域

let messages = ["first line", "second", "third", "etc.."];

for (var i = 0; i < messages.length; i++) {
  //Creating an IIFE
  (function(x, msg) {
    //typical closure, passing x & message to the settimeout
    setTimeout(function() {
      draw(msg[x]);
    }, x * 20 * msg[x].length);
  }(i, messages)) // passing reference of both i, & messages
}
messages = "";
messages = [];

function draw(x, y, z) {
  console.log(x)
}

答案 3 :(得分:1)

您正在尝试在setTimeout中运行逻辑,并且变量i是函数级。这意味着您的超时功能将在for循环和所有同步方法完成后执行。在您的情况下,您的超时功能将在最后一行messages=[]之后执行,并且i的值为messages.length,即循环执行时的4

为避免此问题,请使用自动关闭功能。自闭包将把参数作为同步并存储不会改变的可变功能级别。

这是一个如何使用自我封闭的例子。

messages = ["first line", "second", "third", "etc.."];

for(var i=0; i < messages.length; i++){
    (function(i, message) {
       setTimeout(function () {
          draw(message, x, y+(i*k*f) );
       }, i*20*message.length);
    })(i, messages[i])
}
message = "";
messages = [];

在此示例中,我们避免使用foor循环函数的变量,而是在循环内部创建新函数并传递参数。

答案 4 :(得分:0)

您必须保存当前值。

主要问题是variable's scope,并且共享变量将被覆盖。

messages = ["first line", "second", "third", "etc.."];

// your variable
var x = 1;
var y = 1;
var k = 2;
var f = 3;

for(var i=0; i < messages.length; i++){
  set(messages[i]);
}
message = "";
messages = [];

// set a function scope to save current value
function set(val){
  setTimeout(function () {
      draw(val, x, y+(i*k*f) );
  }, i*20*val.length);
}

// your draw function
function draw(a, b, c){
  console.log(a);
}