实习快有一个月了,开心的是我司前端技术团队还是有技术分享的,每一次的分享都是针对项目而言,是有一点高逼格,动不动讲源码😲,自己也突然被安排讲,依然选了JavaScript运行机制
什么是JavaScript?
刚开始学习的时候,看了很多的书,给我们的定义是: JavaScript = ECMAScript + DOM + BOM,可是当深入的时候,我才发现很多的问题,随着ES6/7的不断推广,发现我们更多学习的是最新的ECMAScript语法而已,当发现Node的存在之后,此时的JavaScript = ECMAScript + 宿主环境API。这一刻,才发现自己的技术是多么的短浅(额,好像我也是会Java和PHP的程序员 )
那JavaScript的特性有哪些呢? 我们熟知的:单线程和非阻塞。
单线程很是比较好理解,就是同个时间只能做一件事情,那非阻塞呢?看了那么多的书籍,并没有对非阻塞进行详细的讲解。但是我们生活中会经常说的阻塞是什么呢?不知道你又没有写过一种可以让整个页面卡住的代码,造成的一种现象就是降低了代码执行的速度,这就是我们说到的阻塞。
JavaScript RunTime
运行时的JavaScript有一个Stack(栈)这是调用栈是函数调用形成的栈幀,Heap(堆)更多存的就是对复杂类型数据的引用,而Queue(队列)是一个 JavaScript 运行时包含了一个待处理的消息队列。
举例
|
|
当g函数调用的时候,g函数先入栈,而遇到f函数,而f函数入栈,都f函数执行到return的时候,f函数出栈,随后至g函数出栈。
问题一
以上算是一个知识点的巩固,我们立即抛出一个问题:
输出的结果的顺序,上次滴滴二面最后的一个问题,先说一下这里要讲到事件循环(event-loop)
。
答案很明了就是
代码是由上至下解析执行的,而我们也说过JavaScript是单线程,这里有一个问题,运行到setTimeout的时候,之后仿佛出栈了,在运行到script end的console里面,那之前的回调函数是消失了吗?
这样的原因真的很少人能说上来了!本着深究的原理,我自己整理了一下思路。上文说过,JavaScript有一部分就是宿主环境给JavaScript提供了很多可用的API,而我们通常是在浏览器当中的。
所以这段代码是跑在浏览器中的,而浏览器中解析执行的JavaScript的东西是V8引擎
那我们来看看V8里面有什么呢?其实和JavaScript RunTime并没特大的区别,只是多了其他的API,具体是什么目前还说不上来。
但是我们说过,代码是在浏览器中执行的呀,我们来看看浏览器里有什么:
所以说,问题一的回答是这样的,执行到了setTimeout的时候,由于这是浏览器提供的API,交到了一个叫做WebAPI的地方帮我们托管这个代码,当时候对到1秒的时候,将回调函数放进了callback queue里面,event-loop会帮忙看调用栈是不是清空的状态,如果是,则将回调队列里的函数放进调用栈中执行。
问题二
那如下的代码怎样输出呢?
不同的浏览器有不一样的输出结果,以下是由Chrome 60.03112.113版本输出结果:
这里会有一个细分的过程,任务队列是有分级的,下面有一个是 macro-task(宏任务),另一个是 micro-task(微任务),在最新标准中,它们被分别称为task与jobs。
- macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
- micro-task大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
其实还上述问题一的答案差不多,只不过中间会有一个微任务的出现,优先级是微任务在宏任务之前。
本文可能会有一些错误的地方,欢迎指出,一起交流(拖延有点严重,拖了好几天,最后20分钟码出来了☺)。参考资料