Home > Web Front-end > JS Tutorial > body text

Single thread of setTimeout in JavaScript

黄舟
Release: 2017-12-05 13:23:52
Original
1581 people have browsed it

For a long time, everyone has been saying that Javascript is single-threaded. The browser has only one thread running the JavaScript program at any time. The setTimeout method in JavaScript is more useful and is usually used on the page. Refreshed, delayed execution, etc., but many JavaScript novices still don’t know much about the usage of setTimeout. Today I will introduce to you the single thread of setTimeout in JavaScript!

However, I don’t know if you have any doubts - isn’t our setTimeout (similar to setInterval and Ajax) executed asynchronously during the programming process? ! !

For example:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            console.log("a");            
            //利用setTimeout延迟执行匿名函数            
            setTimeout(function(){
                console.log("b");
            },100);
            console.log("c");       
             </script>
    </body>
    </html>
Copy after login

Run the code and open the chrome debugger, you will get the following results

This result is easy to understand, because the content in my setTimeout is executed after 100ms. Of course, a is output first, then c, and then b in setTimeout is output after 100ms.

Hey, isn’t Javascript single-threaded? Can it be multi-threaded? ! !

Actually, no. setTimeout does not break the single-threaded mechanism of JavaScript, it is actually still single-threaded.

Why do you say this? Then you have to understand what setTimeout is.

Please look at the code below and guess the result:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            var date = new Date();            
            //打印才进入时的时间            
            console.log(&#39;first time: &#39; + date.getTime());            
            //一秒后打印setTimeout里匿名函数的时间            
            setTimeout(function(){                
            var date1 = new Date();
                console.log(&#39;second time: &#39; + date1.getTime() );
                console.log( date1.getTime() - date.getTime() );
            },1000);            
            //重复操作
            for(var i=0; i < 10000 ; i++){
                console.log(1);
            }        
            </script>
    </body>
    </html>
Copy after login

After reading the above code, guess what the output result is? 1000 milliseconds?

We open the chrome debugger, see the picture below

Nani, why is it not 1000 milliseconds? ! ! !

Let’s take a look at the following code again:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            //一秒后执行setTimeout里的匿名函数,alert下            
            setTimeout(function(){
                alert("monkey");
            },1000);            
            while(true){};        
            </script>
    </body></html>
Copy after login

After running the code!

Holy crap, why do I keep refreshing, the browser is stuck, and there is no alert! !

Logically speaking, even if my while loops infinitely, I have to alert after 1 second.

All kinds of problems have the same reason, JavaScript is single-threaded.

Remember that JavaScript is single-threaded, and setTimeout does not implement multi-threading. The truth behind it is this:

The JavaScript engine runs in a single thread, no matter where the browser is There is only one thread running the JavaScript program at all times.

The kernel of the browser is multi-threaded. They cooperate with each other under the control of the kernel to maintain synchronization. A browser implements at least three resident threads: JavaScript engine thread, GUI rendering thread, browser event trigger thread.

*JavaScript engine is based on event-driven single-thread execution. The JavaScript engine has been waiting for the arrival of tasks in the task queue, and then processes them. No matter what the browser There is only one JavaScript thread running the JavaScript program at all times.

*GUI rendering thread is responsible for rendering the browser interface. When the interface needs to be redrawn (Repaint) or a reflow is caused by some operation ( Reflow), the thread will execute. However, it should be noted that the GUI rendering thread and the JavaScript engine are mutually exclusive. When the JavaScript engine is executed, the GUI thread will be suspended, and GUI updates will be saved in a queue and will be executed immediately when the JavaScript engine is idle.

*Event trigger thread. When an event is triggered, the thread will add the event to the end of the pending queue and wait. JavaScript engine processing. These events can come from the code block currently executed by the JavaScript engine such as setTimeout, or from other threads in the browser kernel such as mouse clicks, Ajax asynchronous requests, etc. However, due to the single-threaded relationship of JavaScript, all these events have to be queued for processing by the JavaScript engine ( Asynchronous code will be executed only when no synchronous code is executed in the thread).

so, through the above explanation, all the above problems can be easily solved.

当setTimeout的延迟时间为0时,大家想想它会怎么执行呢?

例如下面的代码:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            console.log(&#39;a&#39;);
            setTimeout(function(){
                console.log(&#39;b&#39;);
            },0);
            console.log(&#39;c&#39;);
            console.log(&#39;d&#39;);        </script>
    </body></html>
Copy after login

运行代码结果如下:

假设你已经知道Javascript单线程的运行原理了。那么,可能会有这样的疑问:setTimeout的时间为0,都没加到处理队列的末尾,怎么会晚执行呢?不应该立即执行吗?

我的理解是,就算setTimeout的时间为0,但是它仍然是setTimeout啊,原理是不变的。所以会将其加入到队列末尾,0秒后执行。

况且,经过查找资料发现,setTimeout有一个最小执行时间,当指定的时间小于该时间时,浏览器会用最小允许的时间作为setTimeout的时间间隔,也就是说即使我们把setTimeout的毫秒数设置为0,被调用的程序也没有马上启动。

这个最小的时间间隔是多少呢?

这和浏览器及操作系统有关。在John Resig的《Javascript忍者的秘密》一书中提到--Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.(在苹果机上的最小时间间隔是10毫秒,在Windows系统上的最小时间间隔大约是15毫秒),另外,MDC中关于setTimeout的介绍中也提到,Firefox中定义的最小时间间隔(DOM_MIN_TIMEOUT_VALUE)是10毫秒,HTML5定义的最小时间间隔是4毫秒。

说了这么多,setTimeout的延迟时间为0,看来没什么意义嘛,都是放在队列后执行嘛。

非也,天生我材必有用,就看你怎么用咯。抛砖迎玉下。

1、可以用setTimeout的延迟时间为0,模拟动画效果哦。

详情请见下代码:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <div id="container" style="width:100px;height:100px;border:1px solid black;"></div>
        <div id="btn" style="width:40px;height:40px;line-height:40px;margin-top:20px;background:pink;">click</div>
        <script>
            window.onload = function(){
                var con = document.getElementById(&#39;container&#39;);
                var btn = document.getElementById(&#39;btn&#39;); 
                //Params: i 为起始高度,num为预期高度
                function render(i, num) {
                    i++; 
                    con.style.height = i + &#39;px&#39;;
                    //亮点在此
                    if(i < num){
                        setTimeout(function() {
                            render(i, num);
                        },0);
                    }
                    else {
                        con = null;
                        btn = null;
                    }
                };
                btn.onclick = function(){
                    render(100, 200);
                };
            };
        </script>
    </body>
</html>
Copy after login


由于是动画,所以想看其效果,还请各位看官运行下代码哦。

代码第19行中,利用setTimeout,在每一次render执行完成(给高度递增1)后,由于Javascript是单线程,且setTimeout里的匿名函数会在render执行完成后,再执行render。所以可以实现动画效果。

2、可以用setTimeout的延迟时间为0,实现捕获事件哦。

当我们点击子元素时,我们可以利用setTimeout的特性,来模拟捕获事件。

请见如下代码:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <style>    
            #parent {
                width:100px;
                height:100px;
                border:1px solid black;
            }   
            #child {
                width:50px;
                height:50px;
                background:pink;
            }
        </style>
    </head>
    <body>
        <p id="parent">
            <p id="child"></p>
        </p>
        <script>
            //点击子元素,实现子元素的事件在父元素触发后触发            
            window.onload = function(){                
            var parent = document.getElementById(&#39;parent&#39;); 
                var child = document.getElementById(&#39;child&#39;);
                parent.onclick = function(){
                    console.log(&#39;parent&#39;);
                }
                child.onclick = function(){                    
                //利用setTimeout,冒泡结束后,最后输出child                    
                setTimeout(function(){
                        console.log(&#39;child&#39;);   
                    },0);
                }
                parent = null;
                child = null;   
            }        </script>
    </body></html>
Copy after login

执行代码,点击粉红色方块,输出结果:

##2. The delay time of setTimeout is 0
三、setTimeout那些事儿之this

说到this,对于它的理解就是:this是指向函数执行时的当前对象,倘若没有明确的当前对象,它就是指向window的。

好了,那么我们来看看下面这段代码:

<!DOCTYPE html>
    <head>
        <title>setTimeout</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
           var name = &#39;!!&#39;;           
           var obj = {
               name:&#39;monkey&#39;,
               print:function(){
                   console.log(this.name);
               },
               test:function(){                   
               //this.print                   
               setTimeout(this.print,1000);
               }
           }
           obj.test();        
           </script>
    </body></html>
Copy after login

通过chrome调试器,查看输出结果:

咦,它怎么输出的是”!!”呢?不应该是obj里的”monkey”吗?!!

这是因为setTimeout中所执行函数中的this,永远指向window。

不对吧,那上面代码中的setTimeout(this.print,1000)里的this.print怎么指向的是obj呢?!!

注意哦,我这里说的是“延迟执行函数中的this”,而不是setTimeout调用环境下的this。

什么意思?

setTimeout(this.print,1000),这里的this.print中的this就是调用环境下的;

而this.print=function(){console.log(this.name);},这个匿名函数就是setTimeout延迟执行函数,其中的this.name也就是延迟执行函数中的this啦。

嘿嘿,这下明白了吧。

var age = 24;function Fn(){    this.age = 18;
    setTimeout(function(){        //this代表window
        console.log(this);        //输出24,而不是Fn的18
        console.log(this.age);
    },1000);
}new Fn();
Copy after login

咦,那有个疑问,比如我想在setTimeout延迟执行函数中的this指向调用的函数呢,而不是window?!!我们该怎么办呢。

常用的方法就是利用that。

that?

对,that。利用闭包的知识,让that保证你传进去的this,是你想要的。

详情见下:

var age = 24;function Fn(){    //that在此
    var that = this;    this.age = 18;
    setTimeout(function(){
        console.log(that);
        console.log(that.age);
    },1000);
}new Fn();
Copy after login

还有一种方法就是,利用bind。

如下:

var age = 24;function Fn(){    this.age = 18;    //bind传入this
    setTimeout(function(){
        console.log(this);
        console.log(this.age);
    }.bind(this),1000);
}new Fn();
Copy after login

总结:

本文通过实例详细的介绍了关于JavaScript中setTimeout之单线程,相信小伙们对setTimeout有了进一步的了解,希望对你的工作有所帮助!

相关推荐:

JavaScript中setTimeout()的使用详解

JavaScript定时器中关于setTimeout()与setInterval()的详解

javascript函数setTimeout带参数用法实例详解

从setTimeout来谈谈说事件循环模型

The above is the detailed content of Single thread of setTimeout in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!