-1

I have an electron app where clicking a button runs a mining function, which takes a long time to run. I am trying to display the nonce as it changes as an element on the page. However, when I run the function, the page freezes and only changes when the function is finished.

//Mining function
   function mine(index, time, prev, transactions, difficulty) {
        if (index !== 0) {
            this.log(`Mining Block ${index}`);

        }
        const startTime = Date.now();
        let nonce = 0;
        let hash = '';
        while (hash.substring(0, difficulty) !== Array(difficulty + 1).join('0')) {
            nonce++;
            hash = crypto
                .createHash('sha256')
                .update(
                    index.toString() +
                    time.toString() +
                    prev.toString() +
                    transactions.toString() +
                    nonce.toString()
                )
                .digest('hex')
                .toString();

            //Nonce indicator
            $("#nonce").text(`Nonce: ${nonce}`);
        }
        const performanceTime = Date.now() - startTime;
        if (performanceTime <= 60000 && index !== 0) {
            this.difficulty++;
            this.log(`Difficulty Increased. Difficulty Is Now ${this.difficulty}`);
        }
        const seconds = performanceTime / 1000;
        const performance = Math.floor((10 * nonce) / seconds) / 10000;

        if (index !== 0) {
            if (performance !== Infinity && performance >= 25) {
                this.log(`Performance: ${performance} kh/s`);
                $("#performance").text(`Performance: ${performance} kh/s`);
            } else {
                this.log(`Performance Could Not Be Measured`);
                $("#performance").text(`Performance: Error`);
            }
            this.log(`Block ${index} Successfully Mined`);

        }

        return nonce;
    }
        //Call 
        function mineHandler(){mine(props)}
        $("#miningBtn").click(mineHandler);
L. Rothman
  • 103
  • 1
  • 7

1 Answers1

0

This is how browsers work. (And Electron's display is effectively a browser.) There's a single thread which is responsible for both updating the UI and running the client-side JavaScript code. (In Electron it's the "rendering thread.") So while your JavaScript code is running, the UI won't update.

There are two solutions:

  1. Have another thread do the heavy lifting and post updates periodically to the main thread. In a browser you'd do that with a web worker. Apparently you can have web workers with Electron as well, see this example. Or perhaps you could have the work done by your main process rather than your rendering process.

  2. Break up the logic so that you yield back to the browser periodically so it has a chance to update its display.

#1 is probably your better bet for the kind of number crunching you're doing. Here's an example counting from 1 to 1,000,000,000 with updates every 10,000:

// Get the contents of our worker script as a blob
var workerScript = document.getElementById("worker").textContent;
var blob = new Blob(
    [workerScript],
    {
        type: "text/javascript"
    }
);

// Create an object URL for it
var url = (window.webkitURL || window.URL).createObjectURL(blob);

// Start the worker
var worker = new Worker(url);
worker.addEventListener("message", function(e) {
    if (e && e.data && e.data.type === "update") {
        display.textContent = "Value: " + e.data.value;
    }
});
<script id="worker" type="javascript/worker">
// The type on this script element means the browser
// won't run it directly. It's here so we can turn it
// into a blob to run the worker later.
for (var n = 1; n <= 1000000000; ++n) {
    if (n % 10000 === 0) {
      self.postMessage({type: "update", value: n});
    }
}
</script>
<div id="display">Waiting for worker to start...</div>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875