第一次立即执行 setInterval 函数

Posted

技术标签:

【中文标题】第一次立即执行 setInterval 函数【英文标题】:Execute the setInterval function without delay the first time 【发布时间】:2011-10-04 20:25:27 【问题描述】:

有办法配置javascriptsetInterval方法立即执行该方法,然后用定时器执行

【问题讨论】:

虽然不是原生的。您可以尝试拨打function 一次,然后拨打setInterval() 【参考方案1】:

第一次直接自己调用函数最简单:

foo();
setInterval(foo, delay);

但是,有充分的理由避免setInterval - 特别是在某些情况下,整个负载的setInterval 事件可以在彼此之后立即到达,没有任何延迟。另一个原因是,如果你想停止循环,你必须显式调用 clearInterval,这意味着你必须记住从原始 setInterval 调用返回的句柄。

因此,另一种方法是让foo 自行触发后续调用,而使用setTimeout

function foo() 
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);


// start the cycle
foo();

这保证了调用之间至少delay 的间隔。如果需要,它还可以更轻松地取消循环 - 您只是在达到循环终止条件时不要调用 setTimeout

更好的是,您可以将所有内容包装在一个立即调用的函数表达式中,该表达式创建函数,然后再次调用自身,并自动启动循环:

(function foo() 
    ...
    setTimeout(foo, delay);
)();

定义函数并一次性启动循环。

【讨论】:

为什么更喜欢setTimeout @Sangdol 因为它确保计时器事件在未处理时不会“堆叠”。在某些情况下,整个负载的 setInterval 事件可以在彼此之后立即到达,没有任何延迟。 如果我使用setTimeout方法,如何停止该功能? @GauravBhor,与停止 setInterval 的方式相同,记住 setTimeout 返回的 id,然后调用 clearTimeout(id)... 或者在函数中设置运行或不运行下一个间隔的条件. @DaveMunger 不,因为它不是真正的递归 - 它只是“伪递归”。在浏览器返回事件循环之前,“递归”调用不会发生,此时调用堆栈已完全展开。【参考方案2】:

我不确定我是否理解正确,但您可以轻松地执行以下操作:

setInterval(function hello() 
  console.log('world');
  return hello;
(), 5000);

显然有很多方法可以做到这一点,但这是我能想到的最简洁的方法。

【讨论】:

这是一个很酷的答案,因为它是一个命名函数,可以立即执行并返回自身。正是我想要的。 绝对是一个很酷的解决方案,但可能会给未来阅读的人带来困惑。 你不需要给它一个名字“你好”。您可以改为返回 arguments.callee 并与匿名函数具有相同的功能 @JochenJung arguments.callee 在 ES5 严格模式下不可用 这种 Javascript 代码会让大多数来自其他语言的新 JS 程序员感到困惑。如果你的公司没有很多 JS 人员并且你想要工作安全,那就写一堆这样的东西。【参考方案3】:

由于同样的问题,我偶然发现了这个问题,但如果您需要像setInterval() 一样表现得完全,但没有一个答案有帮助,但只有的区别在于函数在开始时立即调用。

这是我对这个问题的解决方案:

function setIntervalImmediately(func, interval) 
  func();
  return setInterval(func, interval);

此方案的优势:

使用setInterval 的现有代码可以通过替换轻松修改 在严格模式下工作 它适用于现有的命名函数和闭包 您仍然可以使用返回值并稍后将其传递给clearInterval()

例子:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => 
        console.log('hello');
    , 1000);

// clear interval after 4.5 seconds
setTimeout( _ => 
        clearInterval(myInterval);
    , 4500);

老实说,如果你真的需要使用setInterval,那么你也可以替换原来的setInterval。因此,在现有代码之前添加此代码时无需更改代码:

var setIntervalOrig = setInterval;

setInterval = function(func, interval) 
    func();
    return setIntervalOrig(func, interval);

尽管如此,上面列出的所有优点在这里都适用,但不需要替代。

【讨论】:

我更喜欢这个解决方案而不是setTimeout 解决方案,因为它返回一个setInterval 对象。为了避免调用可能在代码中较晚并因此在当前时间未定义的函数,我将第一个函数调用包装在 setTimeout 函数中,如下所示:setTimeout(function() func();,0); 然后在当前处理周期之后调用第一个函数,这也是立即,但更多的错误证明。 您可以使用...args 参数并在每个函数中再次将其用作...args...【参考方案4】:

您可以将setInterval() 包装在提供该行为的函数中:

function instantGratification( fn, delay ) 
    fn();
    setInterval( fn, delay );

...然后像这样使用它:

instantGratification( function() 
    console.log( 'invoked' );
, 3000);

【讨论】:

我认为您应该返回 setInterval 返回的内容。这是因为否则你不能使用 clearInterval。【参考方案5】:

如果你需要的话,这里有一个包装器来美化它:

(function() 
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) 
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    ;
)();

设置setInterval的第三个参数为true,调用setInterval后第一次运行:

setInterval(function()  console.log("hello world"); , 5000, true);

或者省略第三个参数,它会保持原来的行为:

setInterval(function()  console.log("hello world"); , 5000);

一些浏览器支持 additional arguments 的 setInterval,这个包装器没有考虑到;我认为这些很少使用,但如果您确实需要它们,请记住这一点。

【讨论】:

重写本机浏览器功能是很糟糕的,因为当规范发生变化时,它会破坏其他共存的代码。其实 setInterval 目前还有更多参数:developer.mozilla.org/en-US/docs/Web/API/WindowTimers/…【参考方案6】:

这里有一个简单的版本,适合新手,没有任何麻烦。它只是声明函数,调用它,然后开始间隔。就是这样。

//Declare your function here
function My_Function()
  console.log("foo");
    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );

【讨论】:

这正是前几行中接受的答案所做的。这个答案如何增加新内容? 接受的答案继续说不要这样做。我对已接受答案的回复解释了为什么它仍然是一种有效的方法。 OP 特别要求在第一次调用时调用 setInterval 的函数,但接受的答案转移到谈论 setTimeout 的好处。【参考方案7】:

我会建议按以下顺序调用函数

var _timer = setInterval(foo, delay, params);
foo(params)

如果你想在特定条件下clearInterval(_timer),你也可以将_timer传递给foo

var _timer = setInterval(function()  foo(_timer, params) , delay);
foo(_timer, params);

【讨论】:

您能更深入地解释一下吗? 你从第二次调用开始设置定时器,第一次你直接调用fn。【参考方案8】:

因为有人需要将外部this 带入内部,就好像它是箭头函数一样。

(function f() 
    this.emit("...");
    setTimeout(f.bind(this), 1000);
).bind(this)();

如果上述产生垃圾的问题困扰您,您可以改为关闭。

(that => 
    (function f() 
        that.emit("...");
        setTimeout(f, 1000);
    )();
)(this);

或者根据您的代码考虑使用the @autobind decorator。

【讨论】:

【参考方案9】:

为了解决这个问题,我在页面加载后第一次运行该函数。

function foo() ... 

window.onload = function() 
   foo();
;

window.setInterval(function()

    foo(); 
, 5000);

【讨论】:

【参考方案10】:

有一个方便的 npm 包,名为 firstInterval(完全公开,是我的)。

这里的许多示例不包括参数处理,并且在任何大型项目中更改setInterval 的默认行为都是邪恶的。来自文档:

这种模式

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

等同于

firstInterval(callback, 1000, p1, p2);

如果您是浏览器的老派并且不想要依赖项,则可以从the code. 轻松剪切和粘贴

【讨论】:

【参考方案11】:

您可以设置一个非常小的初始延迟时间(例如 100)并在函数内将其设置为您想要的延迟时间:

var delay = 100;

function foo() 
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);

【讨论】:

【参考方案12】:

// YCombinator
function anonymous(fnc) 
  return function() 
    fnc.apply(fnc, arguments);
    return fnc;
  


// Invoking the first time:
setInterval(anonymous(function() 
  console.log("bar");
)(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() 
  console.log("foo");
), 4000);
// Or simple:
setInterval(function() 
  console.log("baz");
, 4000);

好吧,这太复杂了,所以,让我说得更简单一些:

function hello(status )     
  console.log('world', ++status.count);
  
  return status;


setInterval(hello, 5 * 1000, hello( count: 0 ));

【讨论】:

这是大大过度设计的。【参考方案13】:

你的函数的立即异步调用存在问题,因为标准的 setTimeout/setInterval 有一个大约几毫秒的最小超时,即使你直接将它设置为 0。它是由浏览器特定的工作引起的。

一个真正的零延迟代码示例,适用于 Chrome、Safari、Opera

function setZeroTimeout(callback) 
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');

您可以找到更多信息here

在第一次手动调用之后,您可以使用您的函数创建一个间隔。

【讨论】:

【参考方案14】:

其实最快的就是做

interval = setInterval(myFunction(),45000)

这将调用 myfunction,然后每 45 秒再执行一次,这与执行不同

interval = setInterval(myfunction, 45000)

它不会调用它,但只会安排它

【讨论】:

你从哪里得到的? 这仅在myFunction() 确实返回自身时有效。而是修改要由 setInterval 调用的每个函数,这是一种更好的方法来包装 setInterval 一次,就像其他答案所建议的那样。

以上是关于第一次立即执行 setInterval 函数的主要内容,如果未能解决你的问题,请参考以下文章

setTimeout,setInterval计时器不准的问题

JavaScript 计时器

setinterval读法

setTimeOut和setInterval工作原理

setInterval的问题。

Js同步异步机制