zoukankan      html  css  js  c++  java
  • setTimeout的原理及在JavaScript线程执行队列中的位置

    开发中经常使用setTimeout进行一些延迟操作。昨天突然想了解下setTimeout的handler到底在队列中的什么位置特别好奇。今天特地来测试下。

    定义和用法

    setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

    语法

    setTimeout(code,millisec)
    参数描述
    code 必需。要调用的函数后要执行的 JavaScript 代码串。
    millisec 必需。在执行代码前需等待的毫秒数。

     

     

    提示和注释

    提示:setTimeout() 只执行 code 一次。如果要多次调用,请使用 setInterval() 或者让 code 自身再次调用 setTimeout()。

    以上定义来源于w3school.com

     

    JavaScirpt线程

    先了解下浏览器,浏览器是多线程的。

    1. JavaScript引擎线程
    2. 界面渲染线程
    3. 浏览器事件触发线程
    4. Http请求线程

     

    JS运行在浏览器中,是单线程的,每个window一个JS引擎线程。既然是单线程的,的在某个特定的时刻只有特定代码能被执够行,并阻塞其它的代码。(至于ajax的实现这里就不说了。)

    原理

     来了解下setTimeout的简单的原理:

    setTimeout调用的时候,JavaScript引擎会启动定时器timer,大约millisec(ms)以后执行code,当定时器时间到,就把该事件放到主事件队列等待处理。

    注意:

    浏览器JavaScript线程空闲的时候才会真正执行

    为什么呢?因为当JavaScript线程的正在出来其他JavaScript代码时,其实以已经阻塞了其他的代码,其中包括的setTimeout的定时器部分的实现。

     

    代码测试

     

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
    
        <script type="text/javascript">
            function testHandler() {
                console.log("调用了setTimeout的函数");
            }
            window.onload = function () {
                console.log("开始");
    
                console.log("设置setTimeout 100ms");
                setTimeout(testHandler,100);
    
                console.log("休眠1000ms");
                sleep(1000);
                testNext();
                console.log("结束");
            }
            function testNext() {
                console.log("后续执行的函数");
            }
            function sleep(number) {
                var now = new Date();
                var exitTime = now.getTime() + number;
                while (true) {
                    now = new Date();
                    if (now.getTime() > exitTime)
                        return;
                }
            }
        </script>
    </head>
    <body>
    
    </body>
    </html>

    最终浏览器输出的结果:

    此处setTimeout其实只延迟了100ms。而进setTimeout到结束中先模拟休眠了2000ms,然后再执行了testNext函数。但是从测试结果来看实际上testHandler却是在整个队列的最后。这就解释了上诉中说的,setTimeout将code加入到队列的操作必须是在线程空闲的时候才会执行了。

     

     

    millisec参数有什么用?

    上诉测试发现,实际应用中。setTimeout的millisec参数不管你设置多少,实际执行都是在线程的最后,因为在执行一个操作的时候,JavaScript肯定是一直把代码执行完后再走setTimeout绑定的code的。

    那么问题来了。setTimeout(handler,0)和setTimeout(handler,100)在单独使用时,好像并没有区别。(中间执行的代码处理时间超过100ms时)

     

     <script type="text/javascript">
            function testHandler() {
                console.log("调用了setTimeout的函数");
            }
            window.onload = function () {
                console.log("开始");
    
                console.log("设置setTimeout 100ms");
                setTimeout(testHandler,100);
                setTimeout(function () { console.log("调用了setTimeout的函数2"); }, 50);
                console.log("休眠1000ms");
                sleep(1000);
                testNext();
                console.log("结束");
            }
            function testNext() {
                console.log("后续执行的函数");
            }
            function sleep(number) {
                var now = new Date();
                var exitTime = now.getTime() + number;
                while (true) {
                    now = new Date();
                    if (now.getTime() > exitTime)
                        return;
                }
            }
        </script>

     

    输出结果:

     

    个人认为millisec一般在多个setTimeout一起使用的时,需要区分哪个先加入到队列的时候才有用,否则都可以设置成setTimeout(handler,0)(异步操作不在讨论范围内)

     

    以上哪有写的不对的地方欢迎指正学习。^3^

    欢迎转载

    转载注明原创地址:http://www.cnblogs.com/Jersen/p/4887225.html

  • 相关阅读:
    centos 配置php
    Linux下端口被占用解决
    LUOGU P1040 加分二叉树
    bzoj 1057: [ZJOI2007]棋盘制作
    1858: [Scoi2010]序列操作
    poj 2559 Largest Rectangle in a Histogram
    2018/7/19 模拟赛
    SPOJ 2916 GSS5
    BZOJ 4004: [JLOI2015]装备购买
    CF 549B Looksery Party
  • 原文地址:https://www.cnblogs.com/Jersen/p/4887225.html
Copyright © 2011-2022 走看看