区别:
setTimeout(fn,t):
延迟调用, 超过了时间就调用回调函数, 返回一个 id, 使用 clearTimeout(id)取消执行.
注意: 取消了里面的回调函数就不执行了哦, 而不是取消的时候就立即执行, 下面有源码可以自己 cv 试一下.
setInterval(fn,t):
循环调用, 有周期性的调用回调函数, 返回一个 id, 使用 clearInterval(id)取消执行.
- <!DOCTYPE html>
- <HTML>
- <head>
- <meta charset="utf-8">
- <title>
- 菜鸟教程(runoob.com)
- </title>
- <script>
- console.log('333333333333333333333') var aa = setTimeout(() = >{
- console.log("11111111111111")
- },
- 6000) setTimeout(() = >{
- clearTimeout(aa) console.log("2222222222")
- },
- 3000)
- </script>
- </head>
- <body>
- </body>
- </HTML>
在学习这两种延迟函数之前要最好是先了解一下 JS 单线程和任务队列;
举个栗子:
在广场上, 只有一家一点点奶茶店 (CPU), 然后我(一个任务) 要去买奶茶 (执行这个任务), 只能排一条队(JS 的单线程机制), 虽说排队(主线程) 的人很多, 但是一点点工作人员工作速度确实很快, 一般的人付完现金就完了(synchronous 同步任务).
但是到了我的时候, 我想用支付宝支付, 但是打开支付宝需要网络, 需要等待支付宝软件打开 (asynchronous 异步任务, 等待 IO 设备返回结果), 但是为了不影响队列后面的排队者的速度, 所以一点点的工作人员让我去旁边的队列里(任务队列) 去等待, 这个队列里面有加我一起有三个人在启动支付宝, 我排在第三.
然后一段时间过后, 我的和第一个人支付宝打开了(IO 设备返回结果了), 第二个人没打开, 我和第一个人就把二维码展示出来(在任务队列中添加一个事件, 表示相关异步任务可以进入主线程执行了), 但是这个时候主队列里面还有一些人在买奶茶, 所以, 现在工作人员顾不上我.
然后我们就只能一直等待, 直到主队列里面买奶茶的人都走光了, 这个时候工作人员就把我和第一个人加入主队列中, 然后我和第一个人就相继都买到奶茶了, 主队列又没有人了, 于是工作人员又去问第二个人二维码有没有出来,(这个过程叫 Event Loop(事件循环)), 至此基本的单线程和任务队列就完了, 下面再了解一下定时器的特殊原理.
setTimeout(fn,t)
同样的, 又是我 (setTimeout(fn,20) 函数)去买奶茶, 我首先还是去排队, 到我的时候我说我现在不想买, 我要等到 20(设置的时长)毫秒之后再买, 工作人员就说, 好, 那你去任务队列里面去等 20 毫秒吧, 然后我就屁颠屁颠的去了.
20 毫秒后, 还是老样子, 工作人员要等到主队列里面人都走完了再把我拉到主队列里面去, 所以我实际等待的时间 = 我设置的时间 + 设置时间到了之后主队列里面执行的时间, 但是庆幸的是工作人员工作速度非常快, 所以一般主队列里面是没有人的.
注意:
1, 所以即使你设置超时时间为 0, 工作人员也不会立马执行你哦, 还是会把你加到任务队列中的, 谁叫你是 asynchronous(异步任务)
2, 你设置超时时间有用吗? 实际上是没有生效的, 因为 html5 标准规定了 setTimeout 设置超时时间最小值是 4 毫秒, 如果低于这个值就会自动增加, 老版本浏览器更将是把最短时间设为 10 毫秒, 而最要命的是, 如果涉及到 DOM 的变动的都是 16 毫秒一次.
setInterval(fu,t)
同样的, 鸣人 (setInterval(fn,1000) 函数)去买奶茶, 首先还是去排队, 到鸣人的时候, 它不仅要在 1 秒钟之后买, 还要影分身出很多鸣人相继在 1,2,3,4... 之后买, 工作人员同样要他和他的影分身在任务队列后面排队等会, 正常情况下, 主队列没人了, 鸣人和他的影分身们也会在规定的时间里面相继执行.
那么问题来了
假如每个鸣人都很喜欢逼逼叨叨, 那么就会发生这样子的情况:
当一秒钟后第一个鸣人从任务队列中到主队列中的时候, 就一直跟工作人员逼逼叨叨(发生阻塞了, 例如遇到循环不完的 for), 直到第四秒钟才说完(也就是 b 了 3 秒钟), 这个时候第二个鸣人已经超过预定时间的两秒钟了, 然后等到第二个鸣人和工作人员聊得时候又逼逼叨叨不停, 又要 b3 秒钟, 所以第二个鸣人会在第 7 秒 b 完, 同理, 第三个和第四个分别在第 10 秒和第 13 秒 b 完.
鸣人逼逼叨叨的过程如下:
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <meta charset="utf-8">
- <title>
- uaoie.top
- </title>
- <script>
- console.log('333333333333333333333') var y = 0;
- var x = new Date().getTime();
- var d = setInterval(a, 1000);
- function a() {
- y++;
- sleep(3000);
- if (y >= 4) {
- clearInterval(d)
- }
- console.log(new Date().getTime() - x);
- }
- function sleep(sleepTime) {
- var start = new Date().getTime();
- while (true) {
- if (new Date().getTime() - start > sleepTime) {
- break;
- }
- }
- }
- </script>
- </head>
- <body>
- </body>
- </HTML>
导致的情况如下:
全剧终
八, 彩蛋
现在我们可以很轻松的分析一下下面代码的原理(虽然我们都知道结果):
- var aa=new Date().getTime()
- for (var i = 0; i < 4; i++) {
- setTimeout(function() {
- console.log(new Date().getTime() -aa, i);
- }, 1000);
- }
- console.log(new Date().getTime() -aa, i);
先执行第一行, 完了后执行 for, 循环 4 次也就是执行 4 次 setTimeout 函数, 这个 4 个函数同时放在任务队列中.
然后再执行最下面的 config, 所以会先打印 0 秒和 4.
然后等到一秒后, setTimeout 函数从任务队列中出来到主队列, 输出的是 1 秒和 4.
所以效果如下:
来源: https://www.cnblogs.com/Juaoie/p/11446302.html