zoukankan      html  css  js  c++  java
  • 用故事解析setTimeout和setInterval(内含js单线程和任务队列)

    区别:

    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。
    所以效果如下:








  • 相关阅读:
    HTML5中的Range对象的研究
    浅谈移动端开发页面
    你所不了解的javascript操作DOM的细节知识点(一)
    理解Javascript的动态语言特性
    webview与JS的交互
    javascript客户端检测技术
    逐渐深入地理解Ajax
    html5获取地理位置信息API
    Javascript中的Form表单知识点总结
    go语言基础之不同目录
  • 原文地址:https://www.cnblogs.com/Juaoie/p/11446302.html
Copyright © 2011-2022 走看看