JavaScript单线程 & setTimeout定时器

开发 前端
理解JavaScript的单线程的理念对于JavaScript学习,以及掌握其中的一些设计机制非常重要,比如回调、定时器。对于后续学习NodeJS也有很大的帮助。

理解JavaScript的单线程的理念对于JavaScript学习,以及掌握其中的一些设计机制非常重要,比如回调、定时器。对于后续学习NodeJS也有很大的帮助。

[[184669]]

通过先demo,后总结的形式,使得JavaScript的单线程更易于明白。

1 var a = 1;  //全局变量a 
2 function test(){ 
3     var a=2;  //test中变量a 
4     setTimeout(function(){ 
5         alert(a); //输出test中变量a 
6         a=3;  //修改test中变量a 
7     },3000); 
8     a=4//修改test中变量a 
9     setTimeout(function(){ 
10         alert(a); //输出test中变量a 
11         a=5//修改test中变量a 
12    },1000); 
13    alert(a); //输出test中变量a 
14 } 
15 test(); //执行test函数 
16 alert(a); //输出全局变量a 
 
//运行结果:4 1 4 5  
/* 结果解析:先输出test()运行结果4,然后输出之后一行代码的1,然后1000ms之后输出test()中的变量a=4,***3000ms之后输出test()中的变量a=5 */ 
 
/* 
  运行机制: 
     1. JavaScript是单线程,从上往下依次执行 
     2. setTimeout异步方法存放在任务队列中,JS主线程执行完成之后,才会取任务队列中的任务到JS主线程中执行! 
 
     -> 先执行15行,然后执行16行 
     -> 执行15行,调用test()方法 
     -> 调用test()方法,先创建一个a变量,然后将***个setTimeout放到setTimeout对应的线程中执行(启动定时器timer),第8行,修改test中变量a为4,然后将第二个setTimeout添加到setTimeout对应的线程队列中执行,执行13行,输出test中变量a,此时为4;然后执行16行,输出全局变量a,此时为1. 
     -> 1000ms之后,将第二个setTimeout的回调函数,添加到JS任务队列中,3000ms后将***个setTimeout的回调函数,添加到JS任务队列中。 
     -> JS主线程执行完成之后,会执行任务队列的事件,第二个setTimeout优先进入任务队列,所以优先执行,执行第10行,输出test中的变量a,值为4,然后di11行,将test中的变量a修改为5;2000ms之后***个setTimeout进入任务队列,此时JS主线程栈为空,所以将其添加到JS主线程进行执行,第5行,输出test中的变量a,此时变量的值为5,第6行修改test变量a为3. 
*/ 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

由此延伸以下代码:

var a = 1
var date = +new Date(); // 小技巧:通过"+"转换为整数 
function test(){ 
    var a=2;  
    setTimeout(function(){ 
        console.log(a+'--'+ (new Date()-date)); 
        a=3;  
      },3000); 
    a=4
    setTimeout(function(){ 
        console.log(a+'--'+ (new Date()-date)); 
        a=5
   },1000); 
   console.log(a+'--'+ (new Date()-date)); 

while(new Date-date <1000){ 
 

test(); 
console.log(a+'--'+ (new Date()-date)); 
 
//执行结果:4-1000 1-1001 4-2000 5-4001 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

结合以下博客,整理一些重要概念:

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

http://www.cnblogs.com/Mainz/p/3552717.html

1、作为脚本语言,JavaScript主要功能是与用户互动,以及操作DOM。假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? ->So: JavaScript就是单线程。

2、JavaScript的任务分成两种:同步任务和异步任务。同步任务:在主线程上排队执行的任务,只有上一个任务执行完成了,才会执行下一个任务。异步任务:不进入主线程,而进入“任务队列”的任务,只有“任务队列”通知主线程,某个任务队列可以执行了,等主线程执行完成,任务队列才会进入主线程执行。 -> So:只要主线程空了,就会去读“任务队列”,这就是JavaScript的运行机制。

3、主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个事件又叫“事件循环”(Event Loop)。

HTML5规定setTimeout()的第二个参数的最小值(最短间隔),不得低于4ms,如果低于4ms就会自动增加。在此之前,老版本浏览的都将最短时间设置为10ms。另外,对于那些DOM变动(尤其是设计页面重新渲染的部分),通常不会立即执行,而是每16ms执行一次。这是使用requestAnimationFrame()的效果要好于setTimeout()。

4、需要注意的是:setTimeout只是将事件插入“事件队列”,必须等到前面代码(执行栈)执行完,主线程才会去执行他指定的回调函数。如果当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的是时间执行。

Javascript是单线程,单线程就意味着所有任务需要排队。然后会将所有任务分成两类:同步任务和异步任务!同步任务:在主线程上执行的任务,只有前一个任务执行完成,才会执行后一个!异步任务:不进入主线程、而进入“任务队列”的任务。

Js是单线程的,但是浏览器是多线程的!浏览器是事件驱动的!

JS运行在浏览器中,是单线程的,每个window一个JS线程,但是浏览器不是单线程。可能有多个如下线程:

Javascript引擎线程、界面渲染线程、浏览器事件触发线程、Http请求线程。

setTimeout可以改变,js执行顺序。比如:我们想要输出Hello World,world必须在hello之后输出,不管我们代码的顺序怎么样都输出同样的效果,这个时候就可以借助setTimeout。

//代码一 
var date =  +new Date(); 
console.log('Hello',new Date()-date); 
setTimeout(function(){ 
     console.log('world',new Date()-date); 
},500); 
 
//代码二: 
var date =  +new Date(); 
setTimeout(function(){ 
     console.log('World',new Date()-date); 
},500); 
console.log('Hello',new Date()-date); 
 
//以上两个代码运行结果一样,结果都是:先输出Hello ,然后500ms之后输出World![实际运行:501ms] 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

浏览器中定时器也是一个线程!

Javscript是单线程的,ajax请求确实是异步的!原因是ajax请求的时候,是在浏览器的Http请求线程中执行的,执行之后的回调函数会放到Javascript线程中执行!

Summary:

     Javascript是单线程的,浏览器是多线程的,浏览器的线程包括:JS引擎线程、界面渲染线程、浏览器事件线程、Http请求线程。不过不同的浏览器提供的线程是有区别的。一般JS引擎线程和界面渲染线程是互斥的,两个线程不能同时执行,否则,就会出现界面渲染线程和JS线程修改同一个DOM样式的矛盾问题!

责任编辑:张燕妮 来源: 开源中国社区
相关推荐

2024-02-26 00:00:00

JavaScript单线程高效

2010-08-30 08:55:56

JavaScript引

2009-07-10 09:05:20

SwingWorker

2021-01-10 11:21:33

JavaScript语言开发

2020-11-09 09:33:37

多线程

2022-01-04 11:11:32

Redis单线程Reactor

2023-02-28 18:09:53

Javascript定时器

2010-01-28 16:45:44

Android单线程模

2012-08-07 09:27:40

JavaScript

2019-11-25 10:13:52

Redis单线程I

2024-09-27 11:51:33

Redis多线程单线程

2012-02-15 10:26:40

JavaJava Socket

2018-01-11 08:24:45

服务器模型详解

2019-06-17 14:20:51

Redis数据库Java

2023-08-17 14:12:17

2020-06-11 09:35:39

Redis单线程Java

2023-10-15 12:23:10

单线程Redis

2020-10-30 16:20:38

Redis单线程高并发

2020-06-16 14:19:50

Javascript多线程编程

2021-06-11 11:28:22

多线程fork单线程
点赞
收藏

51CTO技术栈公众号