资讯专栏INFORMATION COLUMN

关于 setTimeout 与 setInterval,你需要知道的一切

rottengeek / 484人阅读

摘要:这里是结论,将是更惊艳的那一个。浏览器隔一段时间像服务器发送一个请求,询问这里有没有需要更新的消息。在响应回来时,才会继续发出第二个请求。但是,显然的,这对我们要做的事来说并不算是什么问题。

我们都知道的是setTimout是用来延迟一个简单的动作的,然而,setInterval的目的是用来重复执行某个动作的。

然后,以上只是一半的事实。因为如果一个函数需要在一个间隔时间内重复的执行,你也可以轻松的使用 setTimeout 设定延迟时间,被延迟执行的函数再进行自调用以此实现循环。

所以,这里有2种方法做同样的事

一个用setInterval

var doStuff = function () {
  // Do stuff
};
setInterval(doStuff, 1000);

一个用setTimeout

var doStuff = function () {
    // DoStuff
    setTimeout(doStuff, 1000); 
};
setTimeout(doStuff, 1000);
// 如果你想立即执行函数,可以这样写
var doStuff = function () {
    setTimeout(doStuff, 1000);
}
doStuff();
// 或者,更酷的方式,使用立即执行函数
(function doStuff () {
   // Do Stuff
   setTimeout(doStuff, 1000);
}())

这必然导致下面两个问题

问题:setInterval和self-invoking setTimeout-loops是可以互相替换的吗?
答案:不,当然不行。它们之间有着很细微的区别,但是如果想写出好的代码,这些细微的区别便是你想知道的事。

当然,接下我将会诉说的,第一,我将告诉你,我们通常会遇到什么样的问题,第二,我将开始介绍它们之间细微的区别,这些区别将让我们从这两个选择中选出更具吸引力的那个一,第三,我将告诉你其实根本不用关心另一个。然后。这里是结论,setTimeout将是更惊艳的那一个。接下来我将一点一点解释。

进程堵塞

首先:如果你试着重复调用的函数并不会化太多的时间来跑,那么将不会有任何问题。即使如此,被调用的函数依然会出现2中不同的情况:它既可以在CPU上高集中的运行脚本,或者它也可以在脚本流外先发出一个命令,并等待结果的到来。

我们主要研究先看第二种情况。典型的便是ajax回调:你的脚本并不会等待服务器的响应,它会自己执行到最后,并让回调函数来监听ajax响应。

现在,一些网站想要你保持实时更新,像Gmail,当你获得一封新的邮件时便会刷新你的邮箱。这里服务端有新消息时便实时通知浏览器端的技术,通常叫做ajax轮询。浏览器隔一段时间像服务器发送一个请求,询问这里有没有需要更新的消息。

你也许会想,你很擅长使用setInterval

// 不要这样做
var pollServerForNewMail = function () {
  $.getJSON("/poll_newmail.php", function (response) {
    if (response.newMail) {
      alert(
        "New mail. At last. You made me walk all the way to the server and back every " +
        "second for this, so if this isn"t life-or-death, you got another thing coming."
      );
    }
  });
};
setInterval(pollServerForNewMail, 1000);

其实像上面那样写并不好。因为请求发送出去到回来是需要时间的,但是这段时间谁能保证会比你设置的间隔时间要短呢?

一个典型的初学者的错误,会想将轮询的间隔时间设置的长一点也许可以解决这个问题。然后,事实是,无论你的间隔时间设的是多少,它依然有可能比,ajax响应的时间短。也就是说,有可能会发生,第一个请求还没回来的情况下,第二请求又已经发出去了。而你需要的是两个请求之间有呼吸的空间,而setTimeout便可以解决这个问题。

(function pollServerForNewMail() {
  $.getJSON("/poll_newmail.php", function (response) {
    if (response.newMail) {
      alert(
        "You have received a letter, good sir. " + 
        "I will have a quick lie-down and be on my way shortly."
      );
    }
    setTimeout(pollServerForMail, 1000);
  });
}());

在第一次发出请求,服务器响应之前,不会发生任何事。在响应回来时,才会继续发出第二个请求。当然,这也就意味着,两个轮询之间的时间超过了1秒,这也依赖于各种各样的因素,像网速和服务器的响应速度等。但是,显然的,这对我们要做的事来说并不算是什么问题。

例子

这里有两个例子来更好的进行说明。

var timesRun = 0;
var startTime = new Date().getTime();

var doStuff = function () {
  var now = new Date().getTime();

  // 只跑5次
  if (++timesRun == 5) clearInterval(timer);

  console.log("Action " + timesRun + " started " + (now - startTime) + "ms after script start");

  // Waste some time
  for (var i = 0; i < 100000; i++) {
    document.getElementById("unobtanium");
  }

  console.log("and took " + (new Date().getTime() - now) + "ms to run.");
};

var timer = setInterval(doStuff, 1000);

下面是结果

Action 1 started 1000ms after script start
and took 8ms to run.
Action 2 started 2000ms after script start
and took 8ms to run.
Action 3 started 3004ms after script start
and took 6ms to run.
Action 4 started 4002ms after script start
and took 6ms to run.
Action 5 started 5000ms after script start
and took 6ms to run.

这里并没有多大的意外。这段代码中间的循环花了一点时间,但是setInterval依然很严格的执行了它的计划。在一秒的间隔之间,开始时间之间并没有一点空隙。

现在是setTimeout-loop的例子

var timesRun = 0;
var startTime = new Date().getTime();

var doStuff = function () {
  var now = new Date().getTime();

  console.log("Action " + (timesRun + 1) + " started " + (now - startTime) + "ms after script start");

  // Waste some time
  for (var i = 0; i < 100000; i++) {
    document.getElementById("unobtanium");
  }

  console.log("and took " + (new Date().getTime() - now) + "ms to run.");

  // Run only 5 times
  if (++timesRun < 5) {
    setTimeout(doStuff, 1000);
  }
};

setTimeout(doStuff, 1000);

输出结果

Action 1 started 1010ms after script start
and took 8ms to run.
Action 2 started 2021ms after script start
and took 8ms to run.
Action 3 started 3031ms after script start
and took 5ms to run.
Action 4 started 4037ms after script start
and took 6ms to run.
Action 5 started 5043ms after script start
and took 6ms to run.

这里也并没有太多的意外。我们已经知道setTimeout-loop并不会严格的执行计划,而是在函数下一次调用之前,会给函数它足够的时间执行它里面的代码。

结论

不要使用setInterval,如果你在乎你的时间。setTimeout-loop可以给你足够的时间控制你的脚本和回调,

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80888.html

相关文章

  • 彻底弄懂 JavaScript 执行机制

    摘要:关于这部分有严格的文字定义,但本文的目的是用最小的学习成本彻底弄懂执行机制,所以同步和异步任务分别进入不同的执行场所,同步的进入主线程,异步的进入并注册函数。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定的几行代码,我们需要知道其输出内容和顺序。 因为javascr...

    gyl_coder 评论0 收藏0
  • setTimeout 或者 setInterval关于 Javascript 计时器:需要知道

    摘要:所以,我们可以将理解为计时结束是执行任务的必要条件,但是不是任务是否执行的决定性因素。的意思是,必须超过毫秒后,才允许执行。 先来回答一下下面这个问题:对于 setTimeout(function() { console.log(timeout) }, 1000) 这一行代码,你从哪里可以找到 setTimeout 的源代码(同样的问题还会是你从哪里可以看到 setInterval 的...

    Warren 评论0 收藏0
  • 这一次,彻底弄懂 JavaScript 执行机制

    摘要:事件完成,回调函数进入。主线程从读取回调函数并执行。终于执行完了,终于从进入了主线程执行。遇到,立即执行。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。事件循环事件循环是实现异步的一种方法,也是的执行机制。 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作...

    dreambei 评论0 收藏0
  • js 执行机制 事件循环

    摘要:事件完成,回调函数进入。我们来分析一段较复杂的代码,看看你是否真的掌握了的执行机制第一轮事件循环流程分析如下整体作为第一个宏任务进入主线程,遇到,输出。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。 关于JavaScript 首先js是单线程的,执行任务肯定是一个接着一个。在最新的html5中提出了web-worker,但是JavaScript是单线程这一核心没有改变,一...

    JackJiang 评论0 收藏0
  • JS忍者秘籍中定时器机制详解

    摘要:设置和清除定时器直接引用忍者秘籍中的图片注意定时器的时间间隔设为,也会有几毫秒的延迟。以上参考资料忍者秘籍第章驯服线程和定时器 showImg(https://segmentfault.com/img/remote/1460000015353524?w=1024&h=681); 前言 前段时间刚看完《JS忍者秘籍》,虽说是15年出版的,有些东西是过时了,但像对原型链、闭包、正则、定时器...

    keelii 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<