自己写的代码,执行结果总是在你意料之中吗?

之所以这样问,是因为在日常工作中,有的同事总是对自己写的代码执行结果很惊讶,有时候只能用'见鬼'和'怀疑人生来'来描述。

惊讶源于不理解

今天和大家分享一下JavaScript的核心

单线程与异步

JavaScript是单线程脚本语言

首先我们要明确一点,JavaScript不管怎么执行都是单线程工作,也就是说同一个时间只能做一件事。JavaScript的单线程,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户交互,以及操作DOM。这决定了它只能是单线程,否则会带来很多复杂的同步问题。为了利用多核CPU的计算能力,虽然HTML5提出了Web Worker,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM和BOM。所以,依然没有改变JavaScript是单线程的本质。

既然说Javascript是单线程工作,那怎么还会有异步?这不是自相矛盾吗?

其实,单线程和异步确实不能同时成为一个语言的特性。js选择了成为单线程的语言,所以它本身不可能是异步的,但js的宿主环境(比如浏览器,Node)是多线程的,宿主环境通过某种方式(事件驱动,下文会讲)使得js具备了异步的属性

所以说,一种语言的牛逼往往不是看语言本身,而是看他运行的环境

EventLoop

先看一段金典的代码:

自己写的代码,执行结果总是在你意料之中吗?

我们发现,按照正常的逻辑思维,代码应该依次打印1,2,3。但是现在2却最后打印出来了,说明代码在执行的时候并不是重上到下依次执行(虽然定时器的时间设置为0)

这就要引入一个概念

宏任务

javascript是单线程,在自己的主线程里面跑着的一直是一个一个宏任务,浏览器在执行到定时器函数时,会为定时器函数专门开一个宏任务,也就是下一个宏任务才能执行到定时器函数

执行流程图如下:

自己写的代码,执行结果总是在你意料之中吗?

这就不难理解为什么定时器里面的东西最后打印出来了,同时也说明了定时器在定时的时候有误差的原因(因为他要等着前面的宏任务执行完毕再执行)。

看似很完美,其实才刚刚开始

我们看下面的代码:

自己写的代码,执行结果总是在你意料之中吗?

打印出来的结果和你预期的相同吗?

微任务

有宏任务就的有微任务,就像当大哥就的有小弟一样

当浏览器执行完一个宏任务后,就会看看有没有微任务执行,如果有微任务执行,就会先把当前的微任务执行完,再去执行下一个宏任务

微任务的代表有ajax,回调函数,和Promise

如下执行:

自己写的代码,执行结果总是在你意料之中吗?

主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个过程的这种运行机制又称为Event Loop(事件循环)

总结

整个EventLoop的执行原理好比医生和病人看病

假设只有一个医生,大家都排队(主队)看病,医生一次只能看一个(单线程),但是有的病人需要做检查,那医生就给他开单子,让他拿着单子去做检查(异步),这个时候医生也不能等着什么也不干(浪费资源),然后接着看下面的病人,这时,做检查的那个人回来了,就排到了另一队(辅队)。医生在主队每次看完一个病人都要去看看辅队有没有人做完检查(时间轮询),如果有就会先把辅队的病人看完,然后再去主队里看下一个病人。

来波硬广:感觉有收获就关注哦!


分享到:


相關文章: