JS的单线程问题

昨天电话面试,面试官在问了一个关于setTimeOut()的问题,给我一个场景,在setTimeOut(func2,0)函数前有一个执行了3秒的函数func1(),那么func2会立刻执行吗?(我的回答是不会,先执行完func1()再执行func2()),然后面试官又换一个,把func1()放在setTimeOut()后面,同样设置时间0ms,那么func2()里面的函数会立刻执行吗?(我的回答是会的,这里就答错了,答案是不一定,因为要看主线程内的命令是否已经执行完了)。归根结底,面试官想考察我的地方是js的单线程问题。下面是我查找资料后的一些总结。

一、Javascript是单线程的

单线程,即浏览器只分配给js一个主线程,用来执行任务,但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

为什么JavaScript是单线程的,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完 全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

虽然js是单线程的,但是浏览器内部是多线程的,除了js引擎线程,它还有UI渲染线程、浏览器事件触发线程、http请求线程……

 

二、同步和异步概念

前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面无反应(假死)。

为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步和异步。

"同步模式"就是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;程序的执行顺序与任务的排列顺序是一致的、同步的;

"异步模式"则不进入主线程、而进入”任务队列”(也称消息队列),每一个任务指定回调函数,只要指定过回调函数,这些事件发生时就会进入”任务队列”,等待主线程读取。所谓”回调函数”,就是那些会被主线程挂起来的代码。

 

三、任务队列和事件循环

异步机制,这里要好好了解一下任务队列和事件循环。

请看下图(转引自Philip Roberts的演讲《Help, I’m stuck in an event-loop》)

 

Stack(栈)用来执行同步任务,即那种能立刻执行,不耗时的任务。Heap(堆)用来存储声明的变量、对象。上图中的虚线部分就是主线程,堆(heap)和栈(stack)共同组成了js主线程。下面的callback queue(回调队列也就是任务队列),当出现异步任务时,只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取,执行对应的回调函数。

主线程的读取过程基本上是自动的,只要执行栈一清空,”任务队列”上第一位的事件就自动进入主线程。主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

 

猜你喜欢

转载自blog.csdn.net/Venus_j/article/details/81288077