• 关于事件循环的一些总结


    什么是事件循环?

    JavaScript是一门单线程语言,即当有一个任务在执行的时候,其他任务需要在其后方等待。而在实际场景中,有些任务可以放在比较靠后的位置,比如加载网络资源时候发送的异步请求。总而言之,事件循环就是JavaScript异步执行机制的一种实现方式。

    我们经常性地认知是,JavaScript是按照顺序从上往下执行的,但是看如下代码:

    setTimeout(()=>{
    console.log(111)},0)
    
    cosole.log(222)

    实际上真实操作的话是输出顺序为222,111。这是为什么呢?

    Javascript引擎会智能地将任务分布为同步任务与异步任务。同步任务地话:主代码。异步任务的话,如:setTimeout、Promise、setInterval、nextTick等。

    首先Javascript引擎会将整体script代码放入执行栈中,遇到同步任务则直接进入主线程执行,遇到异步任务时注册回调函数,并将异步任务放入事件队列中等待。

    待主线程中的所有同步任务执行完毕后,才会去事件队列处取任务。根据队列先进先出的特点,最先进入队列的异步任务会被率先执行。

    而在实际场景中,并不是从事件队列中挨个取出异步任务直接执行那么简单。从宏观意义上,我们将JavaScript的任务分为同步任务与异步任务,但在事件循环中,我们将其分为了宏任务与微任务。不同类型的任务会进入不同的事件队列中。

    宏任务:一般的JavaScript同步代码,定时器相关的异步代码setTimeout、setInterval。

    微任务:promise、nextTick等。

    在Javascript引擎执行代码的过程当中,首先将整体代码作为一个宏任务执行,遇到一般的同步代码立即执行,遇到定时器相关如setTimeout这种宏任务,则先将其放入到宏任务事件队列中,遇到Promise这种则将其catch、then函数放到微任务队列中。整体代码,作为第一次宏任务执行完毕后,JavaScript引擎会先到微任务队列中看看有没有任务,如果有的话,就会将其全部执行完毕;如果没有的话,则会进入到下一次宏任务中。也就是说,JavaScript执行机制是按照宏任务-微任务-宏任务-微任务..这样子循环执行。

    根据队列先进先出的特点,取出宏任务事件队列中第一个宏任务会先执行,遇到同步代码立即执行,遇到微任务则继续进入微任务事件队列。待这一次的宏任务执行完毕后,则继续执行所有微任务。如此循环下去,即为事件循环。

    setTimeout(()=>{
    console.log(111)},1000);
    
    new Promise((resolve,reject) =>{
    console.log(222);
    resolve();}).then(() =>{
    console.log(333);});
    console.log(444)

    我们可以把上面的代码看成两次事件循环。

    我们将整体代码作为宏任务让其进入主线程中执行,由于setTimeout事件为一个宏任务,因此我们把它放在宏任务事件队列当中。往下执行的时候,遇到promise里面的立即执行语句,因此我们直接输出222;遇到then函数,我们将其放入到微任务事件队列当中,放在较为后面的顺序。后期还有个444,直接执行输出。接着我们按照宏任务-微任务-宏任务的顺序,可知下一步执行的即为微任务,promise中的then函数,则输出333,最后再输出setTimeout中的111。

    因此顺序为:222、444、333、111.

    注意:即使setTimeout函数的延迟时间设置为0,也不会立即执行。这边将setTimeout的延迟时间设置为0的意思是待主线程空闲后便可执行。因此还是得等到主线程按照宏-微-宏这样的事件循环顺序执行下去。

    既然说到了setTimeout与setInterval,那么我们来复习一下这两个。 

    JS中定时器与延时调用

    1.定时器:规定过多长时间执行一次。

    setInterval(() =>{
    console.log(aaa);},1000)

    这句话的意思为,每隔一秒输出一个aaa,可以执行多次。

    2.延时调用:这个函数不会马上执行,而是过了多久再执行。

    setTimeout(()=>{
    console.log(bbb)
    },1000)



     这句的意思是过一秒再输出bbb,而且只执行一次。

    注意,在每次setInterval之前都要进行一次clearInterval(timer),来把上一次的定时器清除掉,这样就不会使得动画的速度越来越快。如果不使用clearInterval,那么每执行一次,数值都会叠加一次,则会导致越来越快。并且在执行到所设置的边界条件之后,也要使用clearInterval一下让本次的这个动画停掉。

  • 相关阅读:
    投影变换 到 uv坐标 xy/w 齐次坐标
    GdiPlus[19]: IGPPathGradientBrush 之 SetCenterPoint
    GdiPlus[21]: IGPPathGradientBrush 之 InterpolationColors
    GdiPlus[24]: IGPPrivateFontCollection: 分别从文件和内存加载字体
    GdiPlus[23]: IGPFontFamily
    GdiPlus[25]: IGPInstalledFontCollection: 获取已安装的字体列表
    GdiPlus[20]: IGPPathGradientBrush 之 SetFocusScales
    GdiPlus[22]: IGPFont
    可爱的 CreateMessageDialog
    GdiPlus[18]: IGPPathGradientBrush 之 CenterColor、SurroundColors
  • 原文地址:https://www.cnblogs.com/ljylearnsmore/p/14225937.html
Copyright © 2020-2023  润新知