JSFiddle - React, Tailwind, and code Playground

HTML

<button onclick="start()">Click me to start!</button>
<button onclick="stop()">Click me to stop!</button>
<button onclick="handle()">执行耗时任务,观察 PI 的计算情况</button>
<div id="piEstimate">Not started</div>

JavaScript

const timeout = 16 // 默认一帧为16ms
   var requestId = 0;
   var pointsTotal = 0;
   var pointsInside = 0;
   let currentTask = {
     startTime: 0,
     endTime: 0,
   }
   var channel = new MessageChannel();
   var sender = channel.port2; // port2 用来发消息
   channel.port1.onmessage = function(event) {
     if (performance.now() > currentTask.endTime) {
       // 可能是插入了其他宏任务导致该任务过期,直接 rAF
       requestId = requestAnimationFrame(markPoint)
       return
     }
     refinePi(currentTask.endTime)
     requestId = requestAnimationFrame(markPoint)
   }

   function piStep() {
     var r = 1;
     var x = Math.random() * r;
     var y = Math.random() * r;
     return (Math.pow(x, 2) + Math.pow(y, 2) < Math.pow(r, 2))
   }

   function refinePi(deadline) {
     while (performance.now() < deadline) {
       if (piStep()) {
         pointsInside++;
       }
       pointsTotal++;
     }
     currentEstimate = (4 * pointsInside / pointsTotal);
     textElement = document.getElementById("piEstimate");
     textElement.innerHTML = "Pi Estimate: " + currentEstimate;
   }

   function markPoint(timestamp) {
     currentTask.startTime = timestamp
     currentTask.endTime = timestamp + timeout
     // 下轮宏任务
     sender.postMessage("")
   }

   function start() {
     requestId = requestAnimationFrame(markPoint)
   }

   function stop() {
     // alert(1)
     if (requestId)
       window.cancelAnimationFrame(requestId);
     requestId = 0;
   }

   function handle() {
     let start = performance.now()
     while (performance.now() - start < 100) {}
   }