您好、欢迎来到现金彩票网!
当前位置:老k棋牌 > 栈机制 >

前端基础进阶(十二):深入核心详解事件循环机制

发布时间:2019-06-27 08:01 来源:未知 编辑:admin

  JavaScript的学习零散而庞杂,因此很多时候我们学到了一些东西,但是却没办法感受到自己的进步,甚至过了不久,就把学到的东西给忘了。为了解决自己的这个困扰,在学习的过程中,我一直试图在寻找一条核心的线索,只要我根据这条线索,我就能够一点一点的进步。

  前端基础进阶正是围绕这条线索慢慢展开,而事件循环机制(Event Loop),则是这条线索的最关键的知识点。所以,我就马不停蹄的去深入的学习了事件循环机制,并总结出了这篇文章跟大家分享。

  事件循环机制从整体上的告诉了我们所写的JavaScript代码的执行顺序。但是在我学习的过程中,找到的许多国内博客文章对于它的讲解浅尝辄止,不得其法,很多文章在图中画个圈就表示循环了,看了之后也没感觉明白了多少。但是他又如此重要,以致于当我们想要面试中高级岗位时,事件循环机制总是绕不开的线中正式加入了Promise对象之后,对于新标准中事件循环机制的理解就变得更加重要。这就很尴尬了。

  但是很遗憾的是,大神们告诉了大家这个知识点很重要,却并没有告诉大家为什么会这样。所以当我们在面试时遇到这样的问题时,就算你知道了结果,面试官再进一步问一下,我们依然懵逼。

  在学习事件循环机制之前,我默认你已经懂得了如下概念,如果仍然有疑问,可以回过头去看看我以前的文章。

  因为chrome浏览器中新标准中的事件循环机制与nodejs类似,因此此处就整合nodejs一起来理解,其中会介绍到几个nodejs有,但是浏览器中没有的API,大家只需要了解就好,不一定非要知道她是如何使用。比如process.nextTick,setImmediate

  当然新标准中的web worker涉及到了多线程,我对它了解也不多,这里就不讨论了。

  任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。

  setTimeout/Promise等我们称之为任务源。而进入任务队列的是他们指定的具体执行任务。

  来自不同任务源的任务会进入到不同的任务队列。其中setTimeout与setInterval是同源的。

  事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次从macro-task开始,找到其中一个任务队列执行完毕,然后再执行所有的micro-task,这样一直循环下去。

  其中每一个任务的执行,无论是macro-task还是micro-task,都是借助函数调用栈来完成。

  纯文字表述确实有点干涩,因此,这里我们通过2个例子,来逐步理解事件循环的具体顺序。

  首先,事件循环从宏任务队列开始,这个时候,宏任务队列中,只有一个script(整体代码)任务。每一个任务的执行顺序,都依靠函数调用栈来搞定,而当遇到任务源时,则会先分发任务到对应的队列中去,所以,上面例子的第一步执行如下图所示。

  第二步:script任务执行时首先遇到了setTimeout,setTimeout为一个宏任务源,那么他的作用就是将任务分发到它对应的队列中。

  第三步:script执行时遇到Promise实例。Promise构造函数中的第一个参数,是在new的时候执行,因此不会进入任何其他的队列,而是直接在当前任务直接执行了,而后续的.then则会被分发到micro-task的Promise队列中去。

  因此,构造函数执行时,里面的参数进入函数调用栈执行。for循环不会进入任何队列,因此代码会依次执行,所以这里的promise1和promise2会依次输出。

  script任务继续往下执行,最后只有一句输出了globa1,然后,全局任务就执行完毕了。

  第四步:第一个宏任务script执行完毕之后,就开始执行所有的可执行的微任务。这个时候,微任务中,只有Promise队列中的一个任务then1,因此直接执行就行了,执行结果输出then1,当然,他的执行,也是进入函数调用栈中执行的。

  第五步:当所有的micro-tast执行完毕之后,表示第一轮的循环就结束了。这个时候就得开始第二轮的循环。第二轮循环仍然从宏任务macro-task开始。

  这个时候,我们发现宏任务中,只有在setTimeout队列中还要一个timeout1的任务等待执行。因此就直接执行即可。

  这个时候宏任务队列与微任务队列中都没有任务了,所以代码就不会再输出其他东西了。

  这个例子比较简答,涉及到的队列任务并不多,因此读懂了它还不能全面的了解到事件循环机制的全貌。所以我下面弄了一个复杂一点的例子,再给大家解析一番,相信读懂之后,事件循环这个问题,再面试中再次被问到就难不倒大家了。

  这个例子看上去有点复杂,乱七八糟的代码一大堆,不过不用担心,我们一步一步来分析一下。

  第二步,执行过程遇到setTimeout。setTimeout作为任务分发器,将任务分发到对应的宏任务队列中。

  第三步:执行过程遇到setImmediate。setImmediate也是一个宏任务分发器,将任务分发到对应的任务队列中。setImmediate的任务队列会在setTimeout队列的后面执行。

  第四步:执行遇到nextTick,process.nextTick是一个微任务分发器,它会将任务分发到对应的微任务队列中去。

  第五步:执行遇到Promise。Promise的then方法会将任务分发到对应的微任务队列中,但是它构造函数中的方法会直接执行。因此,glob1_promise会第二个输出。

  这个时候,script中的代码就执行完毕了,执行过程中,遇到不同的任务分发器,就将任务分发到各自对应的队列中去。接下来,将会执行所有的微任务队列中的任务。

  其中,nextTick队列会比Promie先执行。nextTick中的可执行任务执行完毕之后,才会开始执行Promise队列中的任务。

  当所有可执行的微任务执行完毕之后,这一轮循环就表示结束了。下一轮循环继续从宏任务队列开始执行。

  这个时候,script已经执行完毕,所以就从setTimeout队列开始执行。

  setTimeout任务的执行,也依然是借助函数调用栈来完成,并且遇到任务分发器的时候也会将任务分发到对应的队列中去。

  只有当setTimeout中所有的任务执行完毕之后,才会再次开始执行微任务队列。并且清空所有的可执行微任务。

  setTiemout队列产生的微任务执行完毕之后,循环则回过头来开始执行setImmediate队列。仍然是先将setImmediate队列中的任务执行完毕,再执行所产生的微任务。

  当setImmediate队列执行产生的微任务全部执行之后,第二轮循环也就结束了。

  当我们在执行setTimeout任务中遇到setTimeout时,它仍然会将对应的任务分发到setTimeout队列中去,但是该任务就得等到下一轮事件循环执行了。例子中没有涉及到这么复杂的嵌套,大家可以动手添加或者修改他们的位置来感受一下循环的变化。

  OK,到这里,事件循环我想我已经表述得很清楚了,能不能理解就看读者老爷们有没有耐心了。我估计很多人会理解不了循环结束的节点。

  当然,这些顺序都是v8的一些实现。我们也可以根据上面的规则,来尝试实现一下事件循环的机制。

  这样,我们就模拟了一个任务队列。我们还可以定义另外一个队列,利用上面的各种方式来规定他们的优先级。

  需要注意的是,这里的执行顺序,或者执行的优先级在不同的场景里由于实现的不同会导致不同的结果,包括node的不同版本,不同浏览器等都有不同的结果。

  弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点就是单线程,而这个线程中拥有唯一的一个事件循环。当然新标准中的web worker涉及到了多线程,但它的原理是利用一个父线程和多个子线程,归根结底来说js仍逃不...

  在上一篇文章里面我大致介绍了JavaScript的事件循环机制,但是最后还留下了一段代码和几个问题。那就从这段代码开始看: 在这段代码里面,setTimeout和Promise都被称之为任务源,来自不同任务源的回调函数会被放进不同的任务队列里面。 setTimeout的回调...

  前言 其实我前面文章对于改变js的执行顺序及多线程都有相关介绍!例如,我们可以用[setTimeout(fn,0)]改变代码执行循序,文章最后也提及了Event Loop(事件循环)。同时,js可以模拟实现多线程。这篇文章,我详细介绍一下js单线程事件循环,及多线程的实现。...

  转载自『前端碎碎念』系列会记录我平时看书或者看文章遇到的问题,一般都是比较基础但是容易遗忘的知识点,你也可能会在面试中碰到。 我会查阅一些资料并可能加上自己的理解,来记录这些问题。更多文...

  欢迎光临我的博客拓跋的前端客栈,如果您发现我文章中存在错误,请尽情向我吐槽,大家一起学习一起进步φ(ω*) 1. 初探 --- setTimeout()的那些事儿 相信很多人在初学JavaScript的时候都遇到过类似的代码: 萌新们看到这个,肯定觉得很简单。part1...

  使人有面前之誉,不若使其无背后之毁;使人有乍交之欢,不若使其无久处之厌。 好好说话是什么 在鲁迅先生那,好好说话是呐喊彷徨。 在诗人林徽因那,好好说话是人间四月天。 在词人李清照那,好好说话是绿肥红瘦。 在我们这,好好说话也许就是用适当温柔的方式真心表达你的感受。 尽可能让...

  在离5800营地直线米的时候,我最担心的事终于降临了——风雪骤然变大。这是真正的暴雪,也是我平生遇到的最疯狂的雪。密集的雪片在疾风的作用下,变成一道道笔直的白线,把灰蒙蒙的天空分割得支离破碎。毫无疑问,用不了多会儿,雪就会把路迹给彻底掩盖。 我开始感到...

  一直想写这件事情,在脑袋中想了好久,偶然又看到他的更新状态,让我有些感想,十多年的感情,说是痴情却道也是傻痴一枚,这段感情在外人看来没有惊天动地,没有温暖岁月,有的只是一个年少的男生在懵懂的年纪遇到了他世界里的一抹阳光,从此历经千帆,维心底留有一隅无人可碰触的角落,那角落会...

http://theenigmaco.com/zhanjizhi/140.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有