宝哥软件园

理解javascript定时器中的单线程

编辑:宝哥软件园 来源:互联网 时间:2021-09-17

1.JavaScript引擎是单线程的。

从下面的代码中可以看出,setTimeout中的第一个代码是一个无限循环。因为是单线程,下面两个定时器就没有机会执行了。

脚本类型=' text/JavaScript ' setTimeout(function(){ while(true){ } },100);SetTimeout(函数(){ alert ('hello!setTimeout’);} , 200);SetInterval(函数(){ alert ('hello!setInterval’);} , 200);/script浏览器的内核是多线程的,它们相互协作,在内核的控制下保持同步。一个浏览器至少有三个常驻线程:javascript引擎线程、GUI渲染线程和浏览器事件触发线程。

JavaScript引擎是基于事件驱动的单线程执行,JS引擎一直在等待任务队列中任务的到来然后进行处理,而浏览器中任何时候都只有一个JS线程在运行JS程序。GUI渲染线程负责渲染浏览器界面,当界面因某种操作需要重新绘制或回流时,就会执行。但是需要注意的是,GUI渲染线程与JS引擎是互斥的。当JS引擎执行时,GUI线程将被挂起,GUI更新将被保存在队列中,并在JS引擎空闲时立即执行。浏览器触发线程,当事件被触发时,线程会将事件添加到待处理队列的末尾,等待JS引擎处理。这些事件可以来自JavaScript引擎当前执行的代码块,如setTimeOut,也可以来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等。然而,由于JS的单线程,所有这些事件都必须排队等待JS引擎处理。

从上图可以看出,浏览器中的JavaScript引擎是事件驱动的,这里的事件可以看作是浏览器分配给它的各种任务。JavaScript引擎一直在等待任务队列中任务的到来。由于单线程关系,这些任务必须由引擎逐个排队和处理。

T1,t2.tn代表不同的时间点,tn下面对应的小方块代表该时间点的任务。

时间t1:

1.图形用户界面渲染线程2。浏览器事件触发线程:t1期间,用户首次点击鼠标按钮,点击被浏览器事件触发线程捕获,形成鼠标点击事件。从图中可以看出,对于JavaScript引擎线程,这个事件被其他线程异步传输到任务队列的末尾,这个鼠标点击事件正在等待处理,因为引擎正在t1处理任务。3.定时触发线程:这里的浏览器模型定时器计数器是不被JavaScript引擎统计的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态,就无法统计时间,必须依靠外部来计时和触发定时,所以队列中的定时事件是异步事件。4.在t1期间,当鼠标点击事件被触发后,先前设置的setTimeout定时也到达。此时,对于JavaScript引擎来说,计时触发器线程已经生成了一个异步计时事件,并将其放入任务队列中,该队列排在click事件回调之后,正在等待处理。同样,在t1期间,增加了某个setInterval定时器,由于间隔计时,在t1期间连续触发两次,这两个事件被安排在队列的末尾进行处理。5.ajax异步请求:浏览器打开一个新的http线程请求。当请求的状态发生变化时,如果之前已经设置了回调,异步线程会生成一个状态变化事件,放入JavaScript引擎的处理队列中进行处理。二是任务的执行顺序不同,显示结果也不同。

1)未使用setTimeout功能。

在网上找到的一个代码示例,这里用来演示。

a href='#' id='doBtn'do某事/a div id=' status '/div脚本类型=' text/JavaScript ' var DoBtn=document。GetElementByID(' DoBtn '),状态=文档。GetElementByID(' status ');函数睡眠(毫秒){ var start=new Date();while(new Date()-start=ms){ } } dobtn。onclick=function(e){ status。innerhtml=' do.请稍候.睡眠(3000);//模拟一个耗时较长的计算过程,3s status.innerHTML=' done '返回false };/script我在火狐浏览器中执行了上面的代码。计划是点击"做点什么"按钮,然后显示"在做什么.请稍等……",接着执行睡觉,最后显示完成。

但是结果是点击后,浏览器卡住3秒左右,最后直接显示完成。

分析下看出,在做status.innerHTML设置的时候,是需要执行图像使用者界面渲染线程的,但是现在还在执行Java脚本语言引擎线程,而Java脚本语言引擎线程与图像使用者界面渲染线程是互斥的,所以就最后显示了完成。

2)使用了setTimeout函数

a href='#' id='doBtn2 '做某事timer/adiv id=' status 2 '/div脚本类型=' text/JavaScript ' var dobtn 2=document。getelementbyid(' dobtn 2 '),状态2=文档。getelementbyid('状态2 ');函数睡眠2(毫秒){ var start=new Date();while(new Date()-start=ms){ } } dobtn 2。onclick=function(e){ status 2。innerhtml=' do '.请等一下…";setTimeout(函数(){ sleep 2(3000);status2.innerHTML=' done},100);返回false };/script在"在做什么.请稍等……"后面加了个setTimeout,延时执行,给了浏览器渲染的时间,这个时候会显示出"在做什么.请稍等……"的字样,然后执行睡眠函数,最后显示完成。

后面有网友发现在火狐浏览器中不起作用,的确有这个问题,后面我修改了一下代码,将局部变量的声明,onclick的绑定放到了window.onload事件中,等页面结构加载完成后,我再做脚本操作。

脚本类型='text/javascript '函数睡眠(毫秒){ //.}窗口。onload=function(){ var doBtn=document。getelementbyid(' doBtn '),状态=文档。getelementbyid(' status ');var dobtn 2=文档。getelementbyid(' dobtn 2 '),状态2=文档。getelementbyid('状态2 ');doBtn.onclick=function(e) { //.};doBtn2.onclick=function(e) { //.};};/script以上就是本文的全部内容,希望对大家的学习有所帮助。

更多资讯
游戏推荐
更多+