【问题标题】:Javascript recursion settimeoutJavascript递归设置超时
【发布时间】:2011-04-05 22:53:08
【问题描述】:

我刚刚开始研究 javascript,所以希望这会很简单。我想制作一个自动播放的图像幻灯片。这非常简单,并且有一些关于它的教程,但由于某种原因我无法让它工作。这就是我所拥有的:

var image1 = new Image();
var image2 = new Image(); 
var image3 = new Image();
image1.src = "images/website6.jpg";
image2.src = "images/website7.jpg";
image3.src = "images/sunset.jpg";
var images = new Array(
  "images/website6.jpg",
  "images/website7.jpg",
  "images/sunset.jpg"
);
setTimeout("delay(images,0)",2000);
function delay(arr,num){
  document.slide.src = arr[num % 3];
  var number = num + 1;
  setTimeout("delay(arr,number)",1000);
}

我要更改的图像有 id slide。而且我也有一些证据表明它有效。发生的是第一个图像加载。然后加载第二个图像(这意味着原始的 setTimeout 调用必须有效)。然后什么也没有发生。对我来说,这表明递归不起作用。

我对其他语言中的递归非常熟悉,所以我认为它一定只是语法之类的东西,但我似乎无法弄清楚。感谢您的帮助。

【问题讨论】:

  • 取消引用第二个 setTimeout 中的参数。这将是我的第一个猜测。
  • @Cronco 有趣的是,如果我这样做,我不会得到第二张图像......这表明这就是让图像改变一次的原因。另外,我看到的每个例子都有引号,这就是我把它们放进去的原因。
  • 引用变量的问题在于计时器正在运行完整的字符串"delay(arr,number)",而不是将变量转换为其存储的值 - 这就是为什么取消引用它会起作用(尽管你仍然需要像这样引用他们...."delay('" + arr + "', '" + number + "')。但是,没有实际意义 - Pointy 的答案更好。我只是在解释发生了什么。
  • 此代码不是递归的。 setTimeout 注册一个处理程序,以便在函数调用堆栈(存在递归函数的地方)被清除时由事件循环异步调用。

标签: javascript recursion settimeout


【解决方案1】:

问题在于,当您将要评估的字符串传递给setTimeout 调用时,评估将在全局上下文中完成(稍后,当需要触发时)。因此,您最好(出于许多其他原因)传递实际函数:

setTimeout(function() { delay(images, 0); }, 2000);

function delay(arr, num) {
  document.slide.src = arr[num % 3];
  setTimeout(function() { delay(arr, num + 1); }, 1000);
}

在更多的modern browsers 中,您可以使用函数的.bind() 方法来创建一个预先绑定到要用作this 的函数的函数:

setTimeout(delay.bind({arr: images, num: 0}), 2000);

function delay() {
  document.slide.src = this.arr[this.num % 3];
  setTimeout(delay.bind({arr: this.arr, num: this.num + 1}), 1000);
}

六个之一,六个另一个,但只是作为一个例子,表明有多种方法可以做事。

【讨论】:

  • 太棒了,它现在可以工作了。我仍然对为什么我的代码不起作用感到有些困惑。你说它是在“以后,当它开火的时候”评估的。这究竟是什么时候,为什么它永远不会到达那部分?还有为什么使用匿名函数会改变这一点?如果有一些很好的文档涵盖了这一点,那么我会很感激一个链接。谢谢。
  • 问题在于字符串“delay(arr,number)”需要能够获取变量“arr”和“number”才能使其有意义。由于字符串“eval()”的工作方式(现在我想起来了,不管是在 setTimeout 调用时还是之后),它是在与超时函数本身不同的上下文中完成的;这就是语言的工作方式。
  • 当您使用 real 函数时,函数含义的解释发生在您调用“setTimeout()”的实际范围内。该函数确实可以访问那里的局部变量,这也是因为 JavaScript 的工作方式。
  • 我认为在这种情况下使用闭包的第一个版本更好。它避免了绑定,这只是在代码中引入了一个额外的术语(this)。而且由于 setTimeout 是从 delay() 内部调用的,因此不需要第一次 setTimeout 调用,只需调用 delay() 并可能从重复的 setTimeouts 更改为单个 setInterval。
  • @RobG 是的,我同意,但我仅出于教学原因将其包括在内:-)
【解决方案2】:

我会非常怀疑第二个setTimeout 电话。我会通过使用显式函数与字符串表达式来更清楚地说明

setTimeout(function() { delay(arr, number); }, 1000);

【讨论】:

    【解决方案3】:

    更紧凑一点,并将延迟参数传递给setTimeout()

    (function delay(arr, num) {
      document.slide.src = arr[num];
      setTimeout(delay, 1000, arr, (num + 1) % 3);
    })(images, 0);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      • 2022-12-19
      • 2010-11-20
      • 2023-03-30
      相关资源
      最近更新 更多