执行栈和任务队列

执行栈:在同步代码在执行时,会推入到一个执行栈中,然后依次执行里面的函数。
任务队列:在碰到异步任务时就交给其他线程去处理,异步任务完成后,会把回调放入任务队列中等待执行栈来取出执行。等当前执行栈里面所有同步任务执行完成后,就会去任务队列里面取出回调放到执行栈里面执行。
事件循环:通过不断循环去任务队列里面取出异步回调来执行,这个过程就是事件循环,而每一次循环就是一个事件周期或称为一次 tick。
image.png

宏任务和微任务

任务队列又分为宏任务队列和微任务队列。
执行栈在同步代码执行完成后,优先检查微任务队列是否有任务需要执行,如果没有,再去宏任务队列检查是否有任务执行,如此往复。

宏任务特征:

  1. 需要异步线程支持;
  2. 有明确的异步任务需要执行和回调(比如http请求或者定时器)

微任务特征:

  1. 不要要其他异步线程支持;
  2. 没有明确的异步任务需要执行,只有回调;

常见宏任务:

  • setTimeout()
  • setInterval()
  • setImmediate()

常见微任务:

  • promise.then()、promise.catch()、await(后面)
  • new MutaionObserver()
  • process.nextTick()

    定时器误差

    只有当主线程的同步任务执行完后,才会去任务队列里面取回调来执行。
    image.png

    视图更新

    微任务队列执行完成后,也就是一次事件循环结束后,浏览器会执行视图渲染,当然这里会有浏览器的优化,可能会合并多次循环的结果做一次视图重绘,因此视图更新是在事件循环之后,所以并不是每一次操作 Dom 都一定会立马刷新视图。

实战

每次执行一个宏任务,然后执行所有微任务(宏任务队列里面的任务是一个一个执行的,微任务队列是一队一队执行的)

  1. setTimeout(function() {
  2. console.log('4')
  3. })
  4. new Promise(function(resolve) {
  5. console.log('1')
  6. resolve()
  7. }).then(function() {
  8. console.log('3')
  9. })
  10. console.log('2')
  11. // 输出 1 2 3 4
  1. setTimeout(function () {
  2. console.log('6')
  3. }, 0)
  4. console.log('1')
  5. async function async1() {
  6. console.log('2')
  7. await async2()
  8. console.log('5')
  9. }
  10. async function async2() {
  11. console.log('3')
  12. }
  13. async1()
  14. console.log('4')
  15. // 输出 1 2 3 4 5 6
  1. console.log("start");
  2. setTimeout(function () {
  3. console.log("setTimeout1");
  4. const promise2 = new Promise((resolve, reject) => {
  5. console.log("promise2");
  6. resolve();
  7. });
  8. promise2.then(() => {
  9. console.log("then2");
  10. const promise3 = new Promise((resolve) => {
  11. console.log("promise3");
  12. resolve();
  13. });
  14. promise3.then(() => {
  15. console.log("then3");
  16. });
  17. });
  18. }, 1000);
  19. setTimeout(function () {
  20. console.log("setTimeout2");
  21. const promise4 = new Promise((resolve, reject) => {
  22. console.log("promise4");
  23. resolve();
  24. });
  25. promise4.then(() => {
  26. console.log("then4");
  27. });
  28. }, 1000);
  29. const promise1 = new Promise((resolve) => {
  30. console.log("promise1");
  31. resolve();
  32. });
  33. promise1.then(() => {
  34. console.log("then1");
  35. });
  36. console.log("end");
  37. // 输出 start promise1 end then1 setTimeout1 promise2 then2 promise3 then3 setTimeout2 promise4 then4

参考