四道eventloop题目测试你是否理解事件环

171 阅读3分钟

题目1

此时点击button打印什么?

<body>
    <button id="button"></button>
</body>
<script>
    let button = document.getElementById("button");
    button.addEventListener("click", () => {
        Promise.resolve().then(() => console.log("Micro task 1"));
        console.log("Listener 1"); //此时堆栈清空
    });
    button.addEventListener("click", () => {
        Promise.resolve().then(() => console.log("Micro task 2"));
        console.log("Listener 2");
    });
</script>
答案
  • Listener 1
  • Micro task 1
  • Listener 2
  • Micro task 2
  • 解析:
    【首次执行script逻辑】:首先执行script代码块,获取button节点。开始监听第一个点击事件函数,开始监听第二个点击事件函数。结束。
    【button点击时执行逻辑】:首先触发第一个监听函数,执行pormise,然后resolve()。这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。接着打印Listener 1,也就是第一个打印的。此时监听函数的执行栈结束,清空微任务队列。打印Micro task 1。然后触发第二个监听函数,执行pormise,然后resolve()。这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。接着打印Listener 2,此时监听函数的执行栈结束,清空微任务队列。打印Micro task 2。

    题目2

    将上面的题目改一下,此时打印什么?

    
    <body>
        <button id="button"></button>
    </body>
    <script>
        let button = document.getElementById("button");
        button.addEventListener("click", () => {
            Promise.resolve().then(() => console.log("Micro task 1"));
            console.log("Listener 1"); //此时堆栈清空
        });
        button.addEventListener("click", () => {
            Promise.resolve().then(() => console.log("Micro task 2"));
            console.log("Listener 2");
        });
        button.click();
    </script>
    
    答案
  • Listener 1
  • Listener 2
  • Micro task 1
  • Micro task 2
  • 解析:
    【首次执行script逻辑】:首先执行script代码块,获取button节点。开始监听第一个点击事件函数,开始监听第二个点击事件函数。然后执行button.click(),这时触发监听事件,执行栈没有结束,先执行第一个监听事件,执行pormise,然后resolve()。这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。然后打印Listener 1,然后执行第二个监听函数,执行pormise,然后resolve()。这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。然后打印Listener 2。然后执行栈结束,清空微任务队列,先执行第一个then函数,打印 Micro task 1。然后执行第二个then函数,打印Micro task 2

    题目3

    执行完script,打印什么?

    <script>
      Promise.resolve().then(function promise1() {
          console.log('promise1')
      })
      setTimeout(function setTimeout1() {
          console.log('setTimeout1');
          Promise.resolve().then(function promise2() {
              console.log('promise2')
          })
      }, 0)
      setTimeout(function setTimeout2() {
          console.log('setTimeout2')
      }, 0)
    </script>
    
    答案
  • promise1
  • setTimeout1
  • promise2
  • setTimeout2
  • 解析:【执行script逻辑】:执行pormise,然后resolve()。这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。然后遇到setTimeout,属于宏任务,setTImeout整段代码丢进宏任务队列以后,就没了。然后又遇到一个setTimeout,再丢进宏任务队列。这是执行栈就结束了,然后清空微任务,打印promise1。清空完微任务后,这里跳过ui渲染(没涉及修改元素节点,重绘或者回流等),从宏任务队列取出一个任务执行,先进先出,延迟0s后执行setTimeout1,打印setTimeout1,这时promise.then属于微任务队列,丢进微任务队列以后,这一行代码就没了。然后这个宏任务的执行栈就结束了,清空微任务,打印promise2。然后执行剩下一个setTimeout2,延迟0s后打印setTimeout2

    题目4,终极螺旋压哨题

    <script>
     console.log(1);
     setTimeout(function() {
         console.log(2);
     }, 1000);
    
     function test() {
         console.log(3);
         setTimeout(() => {
             console.log(4);
         }, 0);
         console.log(5);
     }
     test();
     new Promise(function(resolve, reject) {
         console.log(6);
         setTimeout(function() {
             console.log(7);
         }, 500);
         resolve();
     }).then(function(res) {
         console.log(8);
     });
     console.log(9);
    </script>
    
    答案
  • 1
  • 3
  • 5
  • 6
  • 9
  • 8
  • 4
  • 7
  • 2
  • 解析:【执行script逻辑】:先打印1,遇到setTimeout丢进宏任务队列,执行test,打印3,遇到setTimeout丢进宏任务队列,打印5,遇到promise,执行里面的函数,打印6,遇到setTimeout丢进宏任务队列,then函数丢进微任务队列,promise这段就没了,然后打印9。整个执行栈结束后,清空微任务,打印8.然后从宏任务队列取出第一个执行延迟1s,执行延迟0s,执行延迟500s。依次打印4,7,2