3

图解JS中的事件循环

 1 year ago
source link: https://www.fly63.com/article/detial/12120
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

更新日期: 2022-09-15阅读: 13标签: 事件分享

扫一扫分享

6323ec5171dda.jpg

1、js单线程,并非指js只有一个线程,而是同一时刻只能有一个线程在工作。

2、js中,主线程之外,还有其他线程,比如事件循环线程,定时器触发线程,http异步线程, 浏览器事件线程。

3、在js主线程中,分为两个子线程,js引擎线程,GUI渲染线程。这两个线程是互斥的,同一时刻只能执行一个,要么执行js,要么渲染html

4、任务队列中,分为宏任务微任务。每次执行任务队列时,先执行微任务,再执行宏任务。

5、通常宏任务指 setTimeout,setInterval,XMLHttprequest,fetch等回调。 微任务指 Promise,MutationObserver等回调。

6、如果在 定时器触发线程、http异步线程、浏览器事件线程中,没有回调,则不会放入队列中。

7、事件循环线程,必须等待主线程中的同步代码执行结束,才会去任务队列再取一个 任务放入 主线程中执行。

//index.js
console.log('a');

  Promise.resolve().then(() => {
    console.log('b');
  });

  setTimeout(() => {
    console.log('c');
  }, 0);


  setTimeout(() => {
    console.log('d');

    Promise.resolve().then(() => {
      console.log('e');
    });
  }, 0);


  console.log('f');

下面是上述代码的执行逻辑:

  1. 遇到console.log('a'); 同步代码,执行,输出a;
  2. 遇到Promise,异步代码,放入任务队列。又因为是promise的回调,属于微任务。标记微任务1
  3. 遇到setTimeout执行,放入定制器触发线程中,定时器触发线程中维护何时倒计时结束,并将回调放入任务队列。又因为setTimeout的回调属于宏任务。标记为宏任务1
  4. 又遇到setTimeout执行,放入定制器触发线程中,将回调放入任务队列。因为setTimeout的回调属于宏任务。标记为宏任务2
  5. 遇到console.log('f'); 同步代码,执行,输出f

此时主线程中的同步代码已经完全执行,控制台输出a,f。主线程是空的。此时事件循环线程发现,任务队列有东西,分别是微任务1,宏任务1,宏任务2.

  1. 按照先执行微任务,再执行宏任务顺序,先将微任务1,即 () => { console.log('b'); } 放入主线程中由js执行。输出b,
  2. 此时主线程执行完,又空了,此时任务队列还有宏任务1,宏任务2。由于宏任务1先放入的,按照队列的先进先出顺序。先将宏任务1放入主线程。即 () => { console.log('c'); },输出c,
  3. 再判断队列中是否有微任务,如果有,则全部执行。如果没有,就继续执行宏任务2.
  4. 将宏任务2放入主线程,即

    () => {
     console.log('d');
    
     Promise.resolve().then(() => {
       console.log('e');
     });
    }

    输出d,遇到promise,异步代码,放入微任务队列。标记为微任务2。此时主线程又空了。

  5. 此时任务队列只有微任务2,没有其他的宏任务和微任务。 最后再执行微任务2。即 () => { console.log('e'); }, 输出e

总结下: 最后输出结果为 a f b c d e

注意:
1、上面的 setTimeout(()=>{}); 属于同步代码,会执行,如果 let timer = setTimeout(()=>{}); 你会发现timer有值,是个数字。但也仅仅是执行 setTimeout后将引用返回,剩下的倒计时和回调。都在定时器触发线程中维护。
2、同样,上面的 Promise.resolve() 也属于同步代码,let p = Promise.resolve() .会发现p有值,是个Promise对象,但也仅仅是执行 Promise.resolve() 后将引用返回,剩下的then中的回调。都在微任务队列中维护。

来自:https://segmentfault.com/a/1190000042485178

链接: https://www.fly63.com/article/detial/12120


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK