前端小白白啦 2024-07-23 22:31 采纳率: 38.2%
浏览 18
已结题

浏览器时间循环 交互事件和延时事件的 优先级与执行问题

为什么 将代码放到全局 点击事件最后不执行 然而通过点击按钮的方式执行 点击事件可以执行

浏览器时间循环 交互事件和延时事件的 优先级与执行问题.

代码说明 通过while执行2s时间阻碍程序执行 在while执行完点击按钮

  <body>
    <button>111111111</button>
    <div>开始</div>
    <script>
      const btn = document.querySelector('button');
      const div2 = document.querySelector('div');
     
      setTimeout(() => {
        console.log('timeout');
      }, 0);
      console.log('script start');
      Promise.resolve().then(() => console.log('promise'));

      let aaa = false;

      btn.onclick = function () {
        console.log('交互队列执行');
      };

      const a = Date.now();
      while (Date.now() - a < 2000) {
        // console.log('==', 1);
      }

      console.log('全局while执行结束');


      div2.onclick = () => {
        const a = Date.now();
        setTimeout(() => {
          console.log('timeout');
        }, 0);
        Promise.resolve().then(() => console.log('promise'));

        btn.onclick = function () {
          console.log('交互队列执行');
        };
        console.log('==', Date.now() - a);
        while (Date.now() - a < 2000) {
          // console.log('==', 1);
        }
      };
    </script>
  • 写回答

33条回答 默认 最新

  • 阿里嘎多学长 2024-07-23 22:31
    关注
    获得0.15元问题酬金

    以下内容由AIGC及阿里嘎多学长共同生成、有用望采纳:


    您的问题涉及到JavaScript的事件循环和执行栈的机制。首先,我们来逐一解答您的问题:

    1. 为什么将代码放在全局点击事件的最后,它不执行,而通过点击按钮的方式,点击事件却可以执行。 这可能是因为在JavaScript中,事件处理器是按照它们被添加的顺序执行的。如果一个元素的点击事件处理器被添加在了另一个元素的全局点击事件处理器之后,那么当点击事件发生时,元素的点击事件处理器会首先被触发。如果全局点击事件处理器试图阻止事件的默认行为或进一步传播,它需要在元素的点击事件处理器之前被添加。

    2. 浏览器中交互事件和延时事件的优先级与执行问题。 在JavaScript中,事件循环由两个主要队列组成:宏任务(Macro Tasks)队列和微任务(Micro Tasks)队列。宏任务包括诸如setTimeoutsetInterval和I/O操作等,而微任务包括Promise回调、MutationObserver等。微任务队列总是在当前宏任务完成后立即执行,而宏任务队列则在当前宏任务及其所有微任务完成后执行。

      在您的代码示例中,setTimeout 设置为0毫秒后执行,它应该在下一个宏任务执行,但由于while循环阻塞了主线程,导致它无法立即执行。当while循环结束时,浏览器会检查微任务队列,然后是宏任务队列,依次执行它们。

    针对您的问题,以下是一些建议:

    • 避免使用长时间的while循环来阻塞主线程,因为这会影响页面的响应性。
    • 理解事件循环机制,合理安排异步代码的执行顺序,确保事件能够按照预期的优先级执行。
    • 使用console.log来跟踪事件处理函数的执行顺序和时间,以便更好地理解事件循环的工作方式。

    针对您的代码,可以进行以下调整:

    • 移除while循环,因为它会阻塞主线程,影响用户体验。
    • 使用setTimeout代替while循环来实现延时效果。
    • 确保事件处理器的注册顺序,以便它们能够按照预期执行。

    以下是调整后的代码示例:

    <body>
      <button id="myButton">111111111</button>
      <div id="myDiv">开始</div>
      <script>
        const btn = document.getElementById('myButton');
        const div2 = document.getElementById('myDiv');
        
        setTimeout(() => {
          console.log('timeout');
        }, 0);
        console.log('script start');
        Promise.resolve().then(() => console.log('promise'));
    
        btn.onclick = function () {
          console.log('按钮点击事件执行');
        };
    
        div2.onclick = () => {
          console.log('div点击事件开始');
          setTimeout(() => {
            console.log('div的setTimeout');
          }, 0);
          Promise.resolve().then(() => console.log('div的Promise'));
    
          // 注册事件处理器,确保顺序
          btn.onclick = function () {
            console.log('div点击后注册的按钮点击事件执行');
          };
    
          console.log('div点击事件结束');
        };
      </script>
    </body>
    

    请注意,事件处理器的注册顺序和执行顺序是关键。在上面的代码中,我们首先注册了按钮的点击事件处理器,然后在div的点击事件处理器中再次注册了按钮的点击事件处理器,这样就可以确保它们按照预期的顺序执行。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 7月31日
  • 赞助了问题酬金15元 7月23日
  • 创建了问题 7月23日

悬赏问题

  • ¥30 stm32f103c8t6制作万能红外遥控器
  • ¥15 有人会fastcrud写前端页面吗
  • ¥15 如何解除Uniaccess管控
  • ¥15 微信小程序跳转关联公众号
  • ¥15 Java AES 算法 加密采用24位向量报错如何处理?
  • ¥15 使用X11可以找到托盘句柄,监控到窗口点击事件但是如何在监听的同时获取托盘中应用的上下文菜单句柄
  • ¥45 字符串操作——数组越界问题
  • ¥15 Loss下降到0.08时不在下降调整学习率也没用
  • ¥15 QT+FFmpeg使用GPU加速解码
  • ¥15 为什么投影机用酷喵播放电影放一段时间就播放不下去了?提示发生未知故障,有什么解决办法吗?