`
nicegege
  • 浏览: 579638 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

js单线程问题

 
阅读更多

最近想做一个东西,大概是这样的。浏览器的滚动条在body头部和底部之间自动移动。移动的过程有速度效果,从慢到快的。也叫加速度效果。

核心代码:

               

var height=$("body").height();//height=2000
while(height>0){
     var temp=200;
     height-=temp;
     if(height>0){
     }else{
          height=0;
     }
     //线程休息2秒
     setTimeout(function(){
          alert(height);
          $("body").scrollTop(height);
     },20000);
}
 

 

 代码运行结果。弹出十个alert,结果均为0。第一次alert后,滚动条会滑动到body头部。

这个和我预想的每个2秒,滚动条从底部向头部移动200像素。结果完全不一样。

看一道js面试题:

<script type="text/javascript">
var t=true;
window.setTimeout(function(){
t=false;
},1000);
while(t){

}
alert('end');
</script>

 运行结果是一直空白,不执行alert弹出框。

上面的种种疑惑的谜底是:

js是单线程的,setTimeout是异步的。js先执行同步代码,执行完后执行异步代码。

在上面面试题中,先执行while(){},由于while是一个死循环所以一直执行,js没有空闲处理异步。所以不会出现alert弹出框。

再解释我做的demo的问题,js先执行while循环,循环结束以后height会变成0,每次循环会执行一次setTimeout异步事件。由于while循环时,js没有空闲处理异步事件所以10次事件会放在js的事件队列中,等待被执行。循环结束以后,js空闲,会执行js事件队列中的事件。执行十次。

 

扩展:

JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序

一、浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程。

1. javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。

2. GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)

4.setTimeout(fn, 500)执行可能比我们自己计划的时间慢,原因是js是单线程,异步代码在同步代码执行完毕的情况下,才会去执行。所以可能有时间延迟。异步代码等待执行的过程中有同步代码要执行,则同步代码先执行。

 

浏览器内核实现原理:

浏览器内核实现允许多个线程异步执行,这些线程在内核的控制下相互配合以确保同步。假如一个浏览器内核的实现至少有三个常驻线程:javascript引擎线程,界面渲染线程,浏览器事件触发线程。除此之外,也有一些执行完成就终止的线程。如http请求线程,这些异步线程会产生不同的异步事件,下面有一个图说明,js引擎和其他线程怎么相互通信的,虽然每个浏览器内核实现细节不同,但是调用原理大同小异。

浏览器执行事件

浏览器内核、js引擎与其他线程通信

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics