微任务、宏任务与Event-Loop

前端之家收集整理的这篇文章主要介绍了微任务、宏任务与Event-Loop前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

代码执行的过程中,必然不会存在同时执行的另一行代码,就像使用以后进行疯狂,如果没有关闭弹框,控制台是不会显示出一条信息的。
代码执行了大量计算,比方说在前端暴力破解密码之类的鬼操作,这就会导致后续代码一直在等待,页面处于假死状态,因为前边的代码并没有执行完。

代码都是同步执行的,这会引发很严重的问题,比方说我们要从远端获取一些数据,难道要一直循环代码去判断是否拿到了返回结果么?
注册一个回调函数,比如说发一个网络请求,我们告诉主程序等到接收到数据后通知我,然后我们就可以去做其他的事情了。
通知到我们,但是此时可能程序正在做其他的事情,所以即使异步完成了也需要在一旁等待,等到程序空闲下来才有时间去看哪些异步已经完成了,可以去执行。

注册一个异步任务就会被放在这个任务队列中,就像在银行中排号,如果叫到你的时候你不在,那么你当前的号牌就作废了,柜员会选择直接跳过进行下一个客户的业务处理,等你回来以后还需要重新取号

添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P爆雷有点儿多,是不是要选择稳一些的理财呢”,然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。
添加的“”而往后推。
?或者 


博客中的代码片段:

 console.log(4))new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)

就是作为宏任务来存在的,而则是具有代表性的微任务,上述代码的执行顺序就是按照序号来输出的。

代码
在实例化的过程中所执行的代码都是同步进行的,而注册的回调才是异步执行的。
代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。
输出结论

代码

 {-  console.log(4)+})+new Promise(resolve => {+  resolve()+  console.log(1)+}).then(_ => {-  console.log(3)+})+console.log(2)

已经先设置了定时器(相当于取号),然后在当前进程中又添加了一些的处理(临时添加业务)。

中实例化,其输出依然会早于的宏任务:

 console.log(4))new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
  Promise.resolve().then(_ => {
    console.log('before timeout')
  }).then(_ => {
    Promise.resolve().then(_ => {
      console.log('also before timeout')
    })
  })
})

console.log(2)

调用的,一般都会在里边有其他的异步操作,比如之类的操作。
注册了一个宏任务,而非是微任务。

中,的实现可以是微任务,也可以是宏任务,但是普遍的共识表示(至少是这么做的),应该是属于微任务阵营的

,说这个也是宏任务,可是在读了以后,发现这很显然是和微任务平行的一个操作步骤
姑且也算是宏任务吧,
为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行

是一个单进程的语言,同一时间不能处理多个任务,所以何时执行宏任务,何时执行微任务?我们需要有这样的一个判断逻辑存在。



 task1// > task2// > task3// > special micro task// > task4// > special macro task

循环来表示,是因为在循环内部可以很方便的进行之类的操作(添加一些任务),从而使迭代的次数动态的增加。

只是负责告诉你该执行那些任务,或者说哪些回调被触发了,真正的逻辑还是在进程中执行的。

的作用,那么在真实的浏览器中是什么表现呢?

这一项感觉有点儿笼统,有太多的东西都可以称之为,点击一次,上传一个文件,与程序产生交互的这些都可以称之为

结构:

  #outer {
    padding: 20px;
    background: #616161;
  }

  #inner {
    width: 100px;
    height: 100px;
    background: #757575;
  }
  

 console.log('promise')) // 注册微任务
  setTimeout(_ => console.log('timeout')) // 注册宏任务
  requestAnimationFrame(_ => console.log('animationFrame')) // 注册宏任务
  $outer.setAttribute('data-random', Math.random()) // DOM属性修改,触发微任务}new MutationObserver(_ => {
  console.log('observer')
}).observe($outer, {
  attributes: true})

$inner.addEventListener('click', handler)
$outer.addEventListener('click', handler)

,其执行顺序一定是: ->  ->  ->  ->  ->  ->  ->  ->  -> 

创建了一个宏任务,也就是说在这次任务中会去触发
两个微任务,遂执行之。
事件会冒泡,所以对应的这次会触发两次函数(、一次在),所以会优先执行冒泡的事件(),也就是说会重复上述的逻辑。
,实际上修改了的属性,这会导致页面的重绘,而这个的操作是同步执行的,也就是说的回调会早于所执行。

元素的触发方式变为,那么会得到不一样的结果。
下的输出顺序大致是这样的:
 ->  ->  ->  ->  ->  ->  ->  -> 

的执行顺序不一样的原因是这样的,因为并不是用户通过点击元素实现的触发事件,而是类似这样的方式,我个人觉得并不能算是一个有效的,在执行了一次回调注册了微任务、注册了宏任务以后,实际上外边的并没有执行完。

,等到这两次都执行完毕后才会去检查有没有微任务、有没有宏任务。

    的这种触发事件的方式个人认为是类似,可以理解为同步执行的代码

 console.log('click'))

document.body.click()
document.body.dispatchEvent(new Event('click'))
console.log('done')// > click// > click// > done

    的监听不会说同时触发多次,多次修改只会有一次回调被触发。

 {
  console.log('observer')  // 如果在这输出DOM的data-random属性,必然是最后一次的值,不解释了}).observe(document.body, {
  attributes: true})

document.body.setAttribute('data-random', Math.random())
document.body.setAttribute('data-random', Math.random())
document.body.setAttribute('data-random', Math.random())// 只会输出一次 ovserver


,文中有动画版的讲解

上与浏览器稍微有些不同,这里是的地址。

以及宏任务的

为一次执行完毕后调用。
则是通过计算一个延迟时间后进行执行。

,而这时定时器已经处于可执行回调的状态了。
,这时才会执行

 console.log('setTimeout'))
setImmediate(_ => console.log('setImmediate'))

一定会在之前触发了:

 console.log('setTimeout'))
setImmediate(_ => console.log('setImmediate'))

let countdown = 1e9while(countdonn--) { } // 我们确保这个循环的执行速度会超过定时器的倒计时,导致这轮循环没有结束时,setTimeout已经可以执行回调了,所以会先执行`setTimeout`再结束这一轮循环,也就是说开始执行`setImmediate`

先执行:

 {
  setTimeout(_ => console.log('timeout'))
  setImmediate(_ => console.log('immediate'))
})// 如果使用一个设置了延迟的setTimeout也可以实现相同的效果

的微任务实现,在代码执行的过程中可以随时插入,并且会保证在下一个宏任务开始之前所执行。

 {  // 这里将永远不会执行
  console.log('init!')
})

对象时是同步执行的,在实例化完成以后就立马发送了事件。
监听事件的这一步。

来解决这个问题:

 {      this.emit('init')
    })    // 同理使用其他的微任务
    // 比如Promise.resolve().then(_ => this.emit('init'))
    // 也可以实现相同的效果  }
}

流程查找有没有微任务,然后再发送事件。

会导致报警,后续的代码永远不会被执行,这是对的,参见上边使用的双重循环实现的即可,相当于在每次循环执行中都对数组进行了操作,这样循环永远也不会结束

本质上还是基于的一些封装,而是属于微任务的一种。所以在使用关键字与效果类似:

 console.log(4))

async function main() {
  console.log(1)
  await Promise.resolve()
  console.log(3)
}

main()

console.log(2)

时传入的代码,await之后的所有代码都是在中的回调

猜你在找的程序笔记相关文章