Precise DOM morphing
morphing typescript dom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update benchmark

+40 -17
+40 -17
benchmark/index.html
··· 349 349 <div class="controls"> 350 350 <div class="control-group"> 351 351 <label for="iterations">Iterations:</label> 352 - <input type="number" id="iterations" value="1000" min="100" max="10000" step="100" /> 352 + <input type="number" id="iterations" value="5000" min="1000" max="50000" step="1000" /> 353 353 354 354 <label for="warmup">Warmup:</label> 355 - <input type="number" id="warmup" value="100" min="10" max="1000" step="10" /> 355 + <input type="number" id="warmup" value="500" min="100" max="5000" step="100" /> 356 356 357 357 <button id="runBtn">🚀 Run Benchmark</button> 358 358 <button id="stopBtn" class="stop" style="display: none">⏹ Stop</button> ··· 407 407 // Allow browser to settle 408 408 await new Promise((resolve) => setTimeout(resolve, 10)) 409 409 410 - // Actual benchmark 410 + // First, do a quick test to see how fast the operation is 411 + const testRun = testCase.setup() 412 + sandbox.appendChild(testRun.from) 413 + const testStart = performance.now() 414 + morphFn(testRun.from, testRun.to) 415 + const testEnd = performance.now() 416 + sandbox.innerHTML = "" 417 + const singleOpTime = testEnd - testStart 418 + 419 + // If operation is very fast (< 0.1ms), batch multiple operations per measurement 420 + const batchSize = singleOpTime < 0.1 ? Math.min(100, Math.ceil(0.1 / Math.max(singleOpTime, 0.001))) : 1 421 + 422 + // Actual benchmark - use higher precision timing with batching 411 423 const times = [] 412 - for (let i = 0; i < this.iterations; i++) { 413 - const { from, to } = testCase.setup() 414 - sandbox.appendChild(from) 424 + const actualIterations = Math.ceil(this.iterations / batchSize) 425 + 426 + for (let i = 0; i < actualIterations; i++) { 427 + // Prepare batch 428 + const batch = [] 429 + for (let j = 0; j < batchSize; j++) { 430 + batch.push(testCase.setup()) 431 + } 415 432 433 + // Measure batch execution 416 434 const start = performance.now() 417 - morphFn(from, to) 435 + for (let j = 0; j < batchSize; j++) { 436 + sandbox.appendChild(batch[j].from) 437 + morphFn(batch[j].from, batch[j].to) 438 + sandbox.innerHTML = "" 439 + } 418 440 const end = performance.now() 419 441 420 - times.push(end - start) 421 - sandbox.innerHTML = "" 442 + const elapsed = (end - start) / batchSize // Average per operation 443 + times.push(elapsed) 422 444 } 423 445 424 - // Calculate statistics 446 + // Calculate statistics with better precision 425 447 const totalTime = times.reduce((a, b) => a + b, 0) 426 448 const averageTime = totalTime / times.length 427 449 const sorted = [...times].sort((a, b) => a - b) 428 450 const median = sorted[Math.floor(sorted.length / 2)] 429 451 const min = sorted[0] 430 452 const max = sorted[sorted.length - 1] 431 - const opsPerSecond = 1000 / averageTime 453 + // Prevent infinity and provide more precision 454 + const opsPerSecond = averageTime > 0 ? 1000 / averageTime : 0 432 455 433 456 return { 434 457 library, 435 458 testName: testCase.name, 436 - iterations: this.iterations, 437 - totalTime, 459 + iterations: actualIterations * batchSize, 460 + totalTime: totalTime, 438 461 averageTime, 439 462 median, 440 463 min, ··· 635 658 <div class="library-name">${result.library}</div> 636 659 <div class="metrics"> 637 660 <div class="metric"> 638 - <div class="metric-value">${result.averageTime.toFixed(3)}</div> 661 + <div class="metric-value">${result.averageTime < 0.001 ? result.averageTime.toExponential(2) : result.averageTime.toFixed(4)}</div> 639 662 <div class="metric-label">ms/op</div> 640 663 </div> 641 664 <div class="metric"> 642 - <div class="metric-value">${Math.round(result.opsPerSecond)}</div> 665 + <div class="metric-value">${result.opsPerSecond > 1000000 ? result.opsPerSecond.toExponential(2) : result.opsPerSecond.toFixed(1)}</div> 643 666 <div class="metric-label">ops/sec</div> 644 667 </div> 645 668 <div class="metric"> 646 - <div class="metric-value">${result.median.toFixed(3)}</div> 669 + <div class="metric-value">${result.median < 0.001 ? result.median.toExponential(2) : result.median.toFixed(4)}</div> 647 670 <div class="metric-label">median ms</div> 648 671 </div> 649 672 </div> ··· 705 728 cardEl.className = "summary-card" 706 729 cardEl.innerHTML = ` 707 730 <div class="summary-library">${index === 0 ? "🏆 " : ""}${data.library}</div> 708 - <div class="summary-score">${data.avgTime.toFixed(3)}ms</div> 731 + <div class="summary-score">${data.avgTime < 0.001 ? data.avgTime.toExponential(2) : data.avgTime.toFixed(4)}ms</div> 709 732 <div style="font-size: 0.9rem; margin-top: 0.5rem;"> 710 733 ${data.wins} test${data.wins !== 1 ? "s" : ""} won 711 734 </div>