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) {}
}