用setTimeout()调用函数

简单的说…

为什么

setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay); 

完美的工作,在指定的延迟之后调用函数,但是

 setTimeout(playNote(currentaudio.id,noteTime), delay); 

同时调用函数playNote?

(这些setTimeout()在for循环中)

或者,如果我的解释太难阅读,这两个函数有什么区别呢?

你列出的第一种forms的工作,因为它将在delay结束时评估一个string。 使用eval()通常不是一个好主意,所以你应该避免这个问题。

第二种方法不起作用,因为你立即用函数调用operator ()执行一个函数对象。 最终发生的是,如果使用表单playNote(...)playNote会立即执行,所以在延迟结束时不会发生任何事情。

相反,你必须传递一个匿名函数setTimeout,所以正确的forms是:

 setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay); 

请注意,您正在传递setTimeout整个函数expression式,所以它将保持匿名函数,并只在延迟结束时执行它。

您也可以传递setTimeout引用,因为引用不会立即执行,但是不能传递参数:

 setTimeout(playNote, delay); 

注意:

对于重复事件,您可以使用setInterval() ,您可以将setInterval()设置为一个variables,并使用该variables通过clearInterval()来停止时间间隔。

你说你在for循环中使用setTimeout() 。 在许多情况下,最好在recursion函数中使用setTimeout() 。 这是因为在for循环中, setTimeout()使用的variables不会像setTimeout()开始时那样是variables,而是函数被触发时的延迟之后的variables。

只需使用recursion函数来回避整个问题。

使用recursion来处理可变延迟时间:

  // Set original delay var delay = 500; // Call the function for the first time, to begin the recursion. playNote(xxx, yyy); // The recursive function function playNote(theId, theTime) { // Do whatever has to be done // ... // Have the function call itself again after a delay, if necessary // you can modify the arguments that you use here. As an // example I add 20 to theTime each time. You can also modify // the delay. I add 1/2 a second to the delay each time as an example. // You can use a condition to continue or stop the recursion delay += 500; if (condition) { setTimeout(function() { playNote(theID, theTime + 20) }, delay); } } 

尝试这个。

 setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay); 

不要使用string超时。 这是一个有效的eval ,这是一件坏事。 它的工作原理是将noteTimenoteTime转换为自己的string表示并将其隐藏在代码中。 这只有在这些值有toString() s时才会起作用,这些toString()会生成JavaScript字面值语法,这将重新创build值,这对于Number是正确的,但对其他值则不是。

 setTimeout(playNote(currentaudio.id, noteTime), delay); 

这是一个函数调用。 playNote被立即调用,函数的返回结果(可能undefined )传递给setTimeout() ,而不是你想要的。

正如其他答案所提到的,你可以使用带闭包的内联函数expression式来引用noteTimenoteTime

 setTimeout(function() { playNote(currentaudio.id, noteTime); }, delay); 

但是,如果你在一个循环中, noteTime或者noteTime都是不同的,你会得到闭环问题:每次超时都会引用同一个variables,所以当它们被调用的时候,你会得到每次都是相同的值,循环完成之前留在variables中的值。

你可以用另一个闭包来解决这个问题,为循环的每个迭代取一个variables值的副本:

 setTimeout(function() { return function(currentaudio, noteTime) { playNote(currentaudio.id, noteTime); }; }(currentaudio, noteTime), delay); 

但是现在变得有些丑陋了。 更好的是Function#bind ,这将部分适用于你的function:

 setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay); 

window是为了在函数内部设置这个值,这是bind()一个特性,在这里你不需要)。

但是,这是ECMAScript第五版function,并不是所有的浏览器都支持。 所以如果你想使用它,你必须先支持,例如:

 // Make ECMA262-5 Function#bind work on older browsers // if (!('bind' in Function.prototype)) { Function.prototype.bind= function(owner) { var that= this; if (arguments.length<=1) { return function() { return that.apply(owner, arguments); }; } else { var args= Array.prototype.slice.call(arguments, 1); return function() { return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments))); }; } }; } 

因为第二个你告诉它首先调用playNote函数,然后将返回值传递给setTimeout。

我从字面上在这个网站上创build了一个帐户来评论Peter Ajtai的回答(目前是最高的投票),但发现你需要50个代表(不pipe是什么)发表评论,所以我会这样做,因为这可能是值得指出的出了几件事情。

他在答复中指出:

您也可以传递setTimeout引用,因为引用不会立即执行,但是不能传递参数:

 setTimeout(playNote, delay); 

这是不正确的。 给setTimeout一个函数引用和延迟量后,任何附加的参数都被parsing为引用函数的参数。 下面会比在一个函数中包装函数调用更好。

 setTimeout(playNote, delay, currentaudio.id, noteTime) 

总是咨询文档。

也就是说,正如Peter所指出的那样,如果您想要改变每个playNote()之间的延迟,那么recursion函数将是一个好主意,或者如果您希望在每个playNote()之间有相同的延迟,可以考虑使用setInterval() playNote()

另外值得注意的是,如果你想parsing你的for循环的一个setTimeout() ,你需要把它包装在一个函数中,详见这里。