summaryrefslogtreecommitdiffstats
path: root/static/crypto.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/crypto.js')
-rw-r--r--static/crypto.js10
1 files changed, 10 insertions, 0 deletions
diff --git a/static/crypto.js b/static/crypto.js
index 0455958..04a1400 100644
--- a/static/crypto.js
+++ b/static/crypto.js
@@ -25,6 +25,14 @@ function leadingZeroBits(bytes) {
return count;
}
+// A loop of only-awaited microtasks (like crypto.subtle.digest) never gives
+// the browser a chance to paint — the event loop keeps draining microtasks
+// before it's willing to render a frame. A macrotask yield (setTimeout) is
+// what actually lets a pending DOM update (e.g. a status message) show up.
+function yieldToBrowser() {
+ return new Promise((resolve) => setTimeout(resolve, 0));
+}
+
// Self-contained hashcash-style proof of work: no challenge round-trip with
// the server. Finds a nonce such that SHA-256("<unix-ts>:<nonce>") has at
// least `difficultyBits` leading zero bits. The server only verifies this,
@@ -32,12 +40,14 @@ function leadingZeroBits(bytes) {
async function computeProofOfWork(difficultyBits) {
const encoder = new TextEncoder();
const ts = Math.floor(Date.now() / 1000);
+ await yieldToBrowser(); // let the "computing proof of work" message paint first
for (let nonce = 0; ; nonce++) {
const stamp = ts + ":" + nonce;
const hash = new Uint8Array(await crypto.subtle.digest("SHA-256", encoder.encode(stamp)));
if (leadingZeroBits(hash) >= difficultyBits) {
return stamp;
}
+ if (nonce % 2000 === 0) await yieldToBrowser(); // keep the tab responsive
}
}