当前位置:   article > 正文

JS高级——浏览器事件循环-微任务、宏任务_浏览器宏任务和微任务

浏览器宏任务和微任务

 JS代码在浏览器中的执行过程在 JS高级——浏览器运行前端项目的原理及流程里面已经介绍了,但是文章中执行的代码都只是一般情况的代码执行,都是从上往下依次执行;实际上在开发中我们会经常使用网络请求(axios)、promiese、setTimeOut、setInterval等异步操作时,那么在执行代码时浏览器会按照什么样的执行顺序来执行呢?接下来让我们来了解浏览器的事件循环机制

1、浏览器中的JavaScript线程

        操作系统中的进程和线程,在这里就不过多解释了,不了解的小伙伴可以查询一下资料。

  1.1 我们知道JavaScript是单线程的,它的容器进程是浏览器或Node。那么浏览器是单个进程吗?进程里面只有一个线程吗?

        答案是目前多数的浏览器其实都是多进程的,当我们打开一个tab页面时就会开启一个新的进程,这是为了防止一个页面卡死而造成所有页面无法响应,整个浏览器需要强制退出;每个进程中又有很多的线程,其中包括执行JavaScript代码的线程。

  1.2 JavaScript的代码执行是在一个单独的线程中执行的

        这就意味着JavaScript的代码,在同一个时刻只能做一件事;如果这件事是非常耗时的,就意味着当前的线程就会被阻塞,所以真正耗时的操作,实际上并不是由JavaScript线程在执行的,是由浏览器的其他线程来完成的,比如网络请求、定时器,我们只需要在特定的时候执行应该有的回调即可。

2、浏览器的事件循环

  2.1 首先我们先来看下事件循环的流程图

        (1)JavaScript线程执行JS代码,会将异步操作分发给浏览器其他线程进行操作;

        (2)然后对异步操作进行分类,划分为微任务队列和宏任务队列;

        (3)最后调用栈会对循环队列中的函数进行回调,在调用栈中执行;

        那么现在问题来了,我们怎么知道异步操作是属于宏任务还是属于微任务?调用栈在调用循环队列中的函数时,调用的优先级是怎么样的呢?

  2.2 宏任务和微任务

        (1)宏任务队列:ajax、setTimeout、setInterval、DOM监听、UI Rendering等;

        (2)微任务队列:Promise的then回调、 Mutation Observer API、queueMicrotask()等;

  2.3 宏任务和微任务优先级

        (1)优先级最高:编写的顶层JS代码,如图中除去setTimeOut函数中的其他代码;

        (2)微任务优先级大于宏任务:在执行每个宏任务之前,要先查看微任务队列中是否有微任务需要执行,如果有则先执行微任务;如果没有则执行当前宏任务。

  2.4 事件循环测试题

        (1)测试题一

  1. setTimeout(function () {
  2. console.log("setTimeout1");
  3. new Promise(function (resolve) {
  4. resolve();
  5. }).then(function () {
  6. new Promise(function (resolve) {
  7. resolve();
  8. }).then(function () {
  9. console.log("then4");
  10. });
  11. console.log("then2");
  12. });
  13. });
  14. new Promise(function (resolve) {
  15. console.log("promise1");
  16. resolve();
  17. }).then(function () {
  18. console.log("then1");
  19. });
  20. setTimeout(function () {
  21. console.log("setTimeout2");
  22. });
  23. console.log(2);
  24. queueMicrotask(() => {
  25. console.log("queueMicrotask1")
  26. });
  27. new Promise(function (resolve) {
  28. resolve();
  29. }).then(function () {
  30. console.log("then3");
  31. });

        我们来画图解析,首先画出三个框分别表示输出值、微任务列表、宏任务列表,顺序都是从上到下,开始都是空的;代码部分内容较多,圈出来使用标签代替;执行玩的部分划掉。如图:

(1)执行第1行,是一个setTimeOut,属于宏任务,所以将part1部分放入宏任务队列;

(2)执行第15行,是一个Promise,函数参数直接执行,所以main script中写入promise1;promise.then()属于微任务,所以将then1放入微任务队列;

(3)执行22行,setTimeOut属于宏任务,将setTimeOut2部分放入宏任务队列;

(4)执行26行,直接输出,main script放入2;

(5)执行28行,queueMicrotask属于微任务,将queueMicrotask1放入微任务队列;

(6)执行32行,promise.then 属于微任务,将then3放入微任务;

        此时,直接执行代码已执行完,下面执行微任务队列和宏任务队列,微任务优先级大于宏任务。

(7)执行微任务then1,将then1放入main script;

(8)执行微任务queueMicrotask1,将queueMicrotask1放入main script;

(9)执行微任务then3,将then3放入main script;

        此时,微任务队列为空,开始执行宏任务。

(10)执行宏任务part1,将setTimeOut1放入main script;Promise.then属于微任务,将part2放入微任务队列;

        此时,微任务中有part2,宏任务中有setTimeOut2,由于微任务优先级大,则执行微任务。

(11)执行微任务part2,Promise.then属于微任务,将part3放入微任务列表;将then2放入main script;

        此时,微任务中有part3,宏任务中有setTimeOut2,由于微任务优先级大,则执行微任务。

(12)执行微任务part2,将then4放入main script;

        此时,微任务队列为空,开始执行宏任务。

(13)执行setTimeOut2,将setTimeOut2放入main script;

        至此,所有代码执行完毕,输出结果顺序为main script中的内容。

        (2)测试题二  过程就不画了,可以自己动手画一画

  1. async function async1() {
  2. console.log('async1 start')
  3. await async2();//其后面执行的代码相当于放进then中,作为微任务
  4. console.log('async1 end')
  5. }
  6. async function async2() {
  7. console.log('async2')
  8. }
  9. console.log('script start')
  10. setTimeout(function () {
  11. console.log('setTimeout')
  12. }, 0)
  13. async1();
  14. new Promise(function (resolve) {
  15. console.log('promise1')
  16. resolve();
  17. }).then(function () {
  18. console.log('promise2')
  19. })
  20. console.log('script end')
  21. // script start
  22. // async1 start
  23. // async2
  24. // promise1
  25. // script end
  26. // async1 end
  27. // promise2
  28. // setTimeout

   

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号