我需要在按钮点击时在浏览器中运行算法。在javascript中对它进行编码非常复杂,而且速度非常慢。有没有推荐的架构呢?理想情况下,我想用C ++或Python编写代码,但我想在按钮点击时无法在浏览器中运行它。那么,我的下一个最佳选择是什么?
我无法在服务器端运行它,因为页面上会有1000次点击,这会导致来回传递过多的信息。
答案 0 :(得分:5)
那么,我的下一个最佳选择是什么
使用网络工作者(specification,MDN),以便计算不在主UI线程上运行。工作人员甚至可以将更新发布到主线程以显示进度。
从您对该问题的评论:
需要同步操作,即点击...
这没有关注,你真的没有希望它是同步的,如果它做得很重,你会锁定浏览器的UI。
如果您需要在处理过程中阻止进一步点击,只需在按钮运行时停用。
这里有一个例子,它可以计算出10亿个因子(即使在现代浏览器上也需要一些时间),每百万人都会得到工人的更新:
HTML:
<input type="button" class="the-btn" value="Click To Start">
<div>
<div class="progress-wrapper">
<div class="progress-bar"></div>
</div>
<div class="progress-counter">-</div>
</div>
<div class="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});
}
};
页面中的主要脚本:
// Get the worker
var worker = new Worker("factorial_worker.js");
// Get our various elements
var btn = document.querySelector(".the-btn");
var progressBar = document.querySelector(".progress-bar");
var progressCounter = document.querySelector(".progress-counter");
var result = document.querySelector(".result");
function setProgress(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;
}
};
实例(由于我们无法在Stack Snippets上执行外部文件,因此可以将工作人员嵌入到页面中):
// <ignore> Ignore this bit, it's just because we can't have a separate file in Stack Snippets
var blob = new Blob([
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 = new Worker(window.URL.createObjectURL(blob));
// Get our various elements
var btn = document.querySelector(".the-btn");
var progressBar = document.querySelector(".progress-bar");
var progressCounter = document.querySelector(".progress-counter");
var result = document.querySelector(".result");
function setProgress(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;
}
};
&#13;
.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;
}
&#13;
<input type="button" class="the-btn" value="Click To Start">
<div>
<div class="progress-wrapper">
<div class="progress-bar"></div>
</div>
<div class="progress-counter"></div>
</div>
<div class="result"></div>
<script class="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>
&#13;