首页 > 解决方案 > 事件循环和同步阻塞

问题描述

我正在浏览“不耐烦的程序员的 JS”,我遇到了以下代码。
我试图了解同步性质以及为什么Blocking...要在sleep(5000).
我相信代码的目的是在Blocking...发生阻塞时出现在屏幕上,但当我在 JSFiddle 中输入它时,这并不是实际响应

document.getElementById('block')
  .addEventListener('click', doBlock);

function doBlock(event) {
  setStatus('Blocking...');
  sleep(5000);
  setStatus('Done');
}

function sleep(milliseconds) {
  const start = Date.now();
  while ((Date.now() - start) < milliseconds);
}

function setStatus(status) {
  document.getElementById('statusMessage')
    .textContent = status;
}
<a id="block" href="#">Block</a>
<div id="statusMessage"></div>
<button>Click me!</button>

标签: javascriptsynchronousevent-loop

解决方案


我可以与以下稍微修改的HTML/JS 代码分享我的发现吗?

  1. Chromium 版本 73.0.3683.75(openSUSE Build)(64 位)按预期工作。
  2. Firefox Developer Edition 67b6(64 位)偶尔会按预期工作。
  3. Firefox Stable Quantum 60.6.1 ESR(64 位)仍然无法按预期工作。

但是,如果您移动到const delayBlocking = 50毫秒延迟,它还会在 Firefox Stable Quantum 60.6.1 ESR 浏览器上显示“Blocking...”。

我的解释是(根据 Mark 在评论中所说的)必须给浏览器时间来更新 DOM。浏览器必须能够呈现至少一帧,显示在进入阻塞状态之前呈现的“阻塞...”状态消息(此处为 5 秒)。这可以通过适当调整的 setTimeout 来完成,如下所示。——问候,M。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Document</title>
</head>
<body>
    <a id="block" href="#">Block</a>
    <div id="statusMessage"></div>
    <button>Click me!</button>

    <script>
     document.getElementById('block')
             .addEventListener('click', doBlock);

     function doBlock(event) {
         setStatus('Blocking...');

         // Introducing some ...
         const delayBlocking = 0;

         setTimeout(function() {
             sleep(5000);
             setStatus('Done');
         }, delayBlocking);
     }

     function sleep(milliseconds) {
         const start = Date.now();
         while ((Date.now() - start) < milliseconds);
     }

     function setStatus(status) {
         document.getElementById('statusMessage')
                 .textContent = status;
     }
    </script>

</body>
</html>

推荐阅读