Long Running Code Inside Html/javascript
Solution 1:
So, what are my next best options
Use a web worker (specification, MDN) so that the calculation isn't running on the main UI thread. The worker can even post updates to the main thread to show progress.
From your comment on the question:
It needs to be synchronous operation i.e on click...
That doesn't follow, and you really don't want it to be synchronous if it's doing heavy-lifting, you'll lock up the UI of the browser.
If you need to prevent further clicks while the processing is going on, just disable the button while it's running.
Here's an example which figures out 1 billion factorial (which takes a few moments even on modern browsers), with updates from the worker every million:
HTML:
<input type="button"class="the-btn" value="Click To Start">
<div><divclass="progress-wrapper"><divclass="progress-bar"></div></div><divclass="progress-counter">-</div></div><divclass="result"></div>
CSS:
.progress-wrapper {
border: 1px solid black;
display: inline-block;
width: 70%;
height: 1em;
}
.progress-bar {
display: inline-block;
width: 0;
background-color: blue;
height: 1em;
}
.progress-counter {
display: inline-block;
}
factorial_worker.js
:
self.onmessage = function(e) {
if (e.data && e.data.type === "start") {
var n = 0, max = 1000000000, result = 0;
while (n < max) {
if (n % 1000000 === 0) {
self.postMessage({type: "progress", progress: (n / max) * 100});
}
result += n;
++n;
}
self.postMessage({type: "done", result: result});
}
};
Your main script in the page:
// Get the workervar worker = newWorker("factorial_worker.js");
// Get our various elementsvar btn = document.querySelector(".the-btn");
var progressBar = document.querySelector(".progress-bar");
var progressCounter = document.querySelector(".progress-counter");
var result = document.querySelector(".result");
functionsetProgress(progress) {
var percent = progress.toFixed(2) + "%";
console.log("Progress: " + percent);
progressCounter.innerHTML = percent;
progressBar.style.width = percent;
}
// Handle clicks
btn.addEventListener("click", function() {
// Disable the button and tell the worker to get started
worker.postMessage({type: "start"});
result.innerHTML = "Working...";
btn.disabled = true;
});
// Handle a message from the worker
worker.onmessage = function(e) {
switch (e.data.type) {
case"progress":
setProgress(e.data.progress);
break;
case"done":
// Re-enable the button
btn.disabled = false;
setProgress(100);
result.innerHTML = "Result: " + e.data.result;
break;
}
};
Live Example (with a trick to embed the worker in the page, since we can't do external files on Stack Snippets):
// <ignore> Ignore this bit, it's just because we can't have a separate file in Stack Snippetsvar blob = newBlob([
document.querySelector(".the-worker").textContent
], { type: "text/javascript" });
// </ignore>// Get the worker// In your own code, you'd refer to a JavaScript file here:// var worker = new Worker("my_worker_script.js");var worker = newWorker(window.URL.createObjectURL(blob));
// Get our various elementsvar btn = document.querySelector(".the-btn");
var progressBar = document.querySelector(".progress-bar");
var progressCounter = document.querySelector(".progress-counter");
var result = document.querySelector(".result");
functionsetProgress(progress) {
var percent = progress.toFixed(2) + "%";
progressCounter.innerHTML = percent;
progressBar.style.width = percent;
}
// Handle clicks
btn.addEventListener("click", function() {
// Disable the button and tell the worker to get started
worker.postMessage({type: "start"});
result.innerHTML = "Working...";
btn.disabled = true;
});
// Handle a message from the worker
worker.onmessage = function(e) {
switch (e.data.type) {
case"progress":
setProgress(e.data.progress);
break;
case"done":
// Re-enable the button
btn.disabled = false;
setProgress(100);
result.innerHTML = "Result: " + e.data.result;
break;
}
};
.progress-wrapper {
border: 1px solid black;
display: inline-block;
width: 70%;
height: 1em;
}
.progress-bar {
display: inline-block;
width: 0;
background-color: blue;
height: 1em;
}
.progress-counter {
display: inline-block;
}
<inputtype="button"class="the-btn"value="Click To Start"><div><divclass="progress-wrapper"><divclass="progress-bar"></div></div><divclass="progress-counter"></div></div><divclass="result"></div><scriptclass="the-worker"type="javascript/worker">// This script won't be parsed by JS engines because its type is javascript/worker.
self.onmessage = function(e) {
if (e.data && e.data.type === "start") {
var n = 0, max = 1000000000, result = 0;
while (n < max) {
if (n % 1000000 === 0) {
self.postMessage({type: "progress", progress: (n / max) * 100});
}
result += n;
++n;
}
self.postMessage({type: "done", result: result});
}
};
</script>
Post a Comment for "Long Running Code Inside Html/javascript"