关于javascript:图解JS中的事件循环

35次阅读

共计 1650 个字符,预计需要花费 5 分钟才能阅读完成。

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 中的回调。都在微工作队列中保护

以上是本人通过浏览其余文章,加上本人了解和本地调试之后的 一点点感想。如有问题,还望斧正。

正文完
 0