通过一道常见的面试题来展开今天的内容介绍吧。

  1. setTimeout(() => {
  2. console.log('set1')
  3. new Promise((resolve, reject) => {
  4. console.log('pro1');
  5. resolve()
  6. }).then(() => {
  7. console.log('then1')
  8. })
  9. });
  10. new Promise((resolve, reject) => {
  11. console.log('pr2');
  12. resolve();
  13. }).then(() => {
  14. console.log('then2');
  15. setTimeout(() => {
  16. console.log('set2');
  17. })
  18. });
  19. setTimeout(() => {
  20. console.log('set3')
  21. })
  22. console.log(4)

看到上面这个题,相信大家在面试中会经常碰到,也是许多面试者害怕和容易采坑的面试题,今天我们就来聊一聊关于这类题的解题原理和思路吧。

JS运行机制

大家都知道,JS的运行机制是从上到下,逐行代码解析运行的。通过下面一张图来解释一下代码的运行机制。

先运行同步队列任务,再运行异步队列任务,异步队列中有微任务,则先执行微任务,然后再执行宏任务,执行宏任务,则会先判断异步队列是否有微任务

图片1.png

异步任务队列运行机制

图片2.png
图片3.png

认识微任务和宏任务

  • 常见的宏任务 setTimeout、setInterval
  • 常见的微任务 process.nextTick、promise.then、catch、finally

**

牛刀小试

  1. setTimeout(() => {
  2. //宏任务
  3. console.log('内层宏事件3')
  4. }, 0)
  5. console.log('外层宏事件1');
  6. new Promise((resolve) => {
  7. console.log('外层宏事件2');
  8. resolve()
  9. }).then(() => {
  10. // 微任务
  11. console.log('微事件1');
  12. }).then(()=>{
  13. // 微任务
  14. console.log('微事件2')
  15. })

解析过程
第一次循环
当代码开始执行的时候,异步任务的微任务和宏任务队列都是空,我们用空数组来表示
当代码碰到 setTimeout 的时候,会把 “内层宏事件3” 放到宏任务队列,此时的宏任务队列是[“内层宏事件3”]
当代码碰到 console.log 的时候,会直接打印出 “外层宏事件1”
当代码碰到 promise 的时候,会直接打印出“外层宏事件2”
当代码碰到 then 的时候,会把“微事件1”放到微任务队列,此时的微任务队列是[“微事件1”]
当再代码碰到 then 的时候,会把“微事件2”放到微任务队列,此时的微任务队列是[“微事件1”, “微事件2”]

第二次循环**
开始执行异步队列的任务,异步队列中包含微任务队列的事件,会直接打印出“微事件1”,此时的微任务队列是[“微事件2”]
当执行完“微事件1”后,会检测当前任务的是否有同步任务,为空时再执行下一个微任务事件
此时同步任务为空,直接打印出“微事件2”,然后再检测是否有同步任务
此时的同步任务和微任务都为空,则实行宏任务,会直接打印出“内层宏事件3”

所以,最终的打印顺序是:外层宏事件1 -> 外层宏事件2 -> 微事件1 -> 微事件2 -> 内层宏事件3

了解了js的运行机制后,当我们再碰这类型的面试题的手,就会轻松许多

给大家留两道面试题吧,练练手

面试题一

  1. setTimeout(() => {
  2. console.log('set1')
  3. new Promise((resolve, reject) => {
  4. console.log('pro1');
  5. resolve()
  6. }).then(() => {
  7. console.log('then1')
  8. })
  9. });
  10. new Promise((resolve, reject) => {
  11. console.log('pr2');
  12. resolve();
  13. }).then(() => {
  14. console.log('then2');
  15. setTimeout(() => {
  16. console.log('set2');
  17. })
  18. });
  19. setTimeout(() => {
  20. console.log('set3')
  21. })
  22. console.log(4)

面试题二

  1. console.log('1');
  2. setTimeout(function() {
  3. console.log('2');
  4. process.nextTick(function() {
  5. console.log('3');
  6. })
  7. new Promise(function(resolve) {
  8. console.log('4');
  9. resolve();
  10. }).then(function() {
  11. console.log('5')
  12. })
  13. })
  14. process.nextTick(function() {
  15. console.log('6');
  16. })
  17. new Promise(function(resolve) {
  18. console.log('7');
  19. resolve();
  20. }).then(function() {
  21. console.log('8')
  22. })
  23. setTimeout(function() {
  24. console.log('9');
  25. process.nextTick(function() {
  26. console.log('10');
  27. })
  28. new Promise(function(resolve) {
  29. console.log('11');
  30. resolve();
  31. }).then(function() {
  32. console.log('12')
  33. })
  34. })