Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript线程的理解 #38

Open
fredshare opened this issue Jun 23, 2017 · 0 comments
Open

Javascript线程的理解 #38

fredshare opened this issue Jun 23, 2017 · 0 comments
Labels

Comments

@fredshare
Copy link
Owner

fredshare commented Jun 23, 2017

单线程的JS引擎

JS单线程原因:如果多线程,那么删除或者创建dom元素,都需要在线程之间通信。因为浏览器不确定dom状态。所以,js设计之初就是单线程。
好处:简单,没有线程切换维护开销,省内存。

多线程的浏览器

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

浏览器一般至少实现三个常驻线程:JS引擎线程,GUI渲染线程,浏览器事件触发线程。

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

JS引擎的工作机制是:当线程中没有执行任何同步代码的前提下才会执行异步代码,setTimeout是异步代码,所以setTimeout只能等JS引擎空闲才会执行,但死循环是永远不会空闲的,所以setTimeout也永远不会执行。

一道面试题:js中在一个时间节点执行

var startTime = +(new Date()),endTime;
setTimeout(function(){
    endTime = +(new Date());
    console.log(1);
    console.log(endTime - startTime);
    },3000);
setTimeout(function(){
    endTime = +(new Date());
    console.log(2);
    console.log(endTime - startTime);
    },2000);
while(+(new Date()) - startTime < 5000){}
console.log(+(new Date()) - startTime);

请问alert(1)和alert(2)的先后顺序和时间间隔。

5s钟的同步执行完之后,开始执行setTimeout异步代码,因为第二个插入的时间间隔早,先执行。
image
因为5s时间超过了3s,所以两个函数几乎同时执行。如果同步时间是1s,那就是2s之后执行第二个函数,3s后执行第一个函数。
image

setTimeout(function(){},0)

setTimeout(..) 并没有把你的回调函数挂在事件循环队列中。它所做的是设 定一个定时器。
当定时器到时后,环境会把你的回调函数放在事件队列中,如果这时候事件循环中已经有 20 个项目了会怎样呢?你的回调就会等待,定时器只能确保你的回调函数不会在指定的 时间间隔之前运行,但可能会在那个时刻运行,也可能在那之后运行,要根据事件队列的 状态而定(PS: 这就是造成定时器不准确的缘由)。

setTimeout(..0)(hack)进行异步调度,基本上它的意思就是把这个函数插入到当前事件循环队列的结尾处。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant