html / javascript

时间:2017-09-21 14:14:27

标签: javascript web

我需要在按钮点击时在浏览器中运行算法。在javascript中对它进行编码非常复杂,而且速度非常慢。有没有推荐的架构呢?理想情况下,我想用C ++或Python编写代码,但我想在按钮点击时无法在浏览器中运行它。那么,我的下一个最佳选择是什么?

我无法在服务器端运行它,因为页面上会有1000次点击,这会导致来回传递过多的信息。

1 个答案:

答案 0 :(得分:5)

  

那么,我的下一个最佳选择是什么

使用网络工作者(specificationMDN),以便计算不在主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上执行外部文件,因此可以将工作人员嵌入到页面中):

&#13;
&#13;
// <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;
&#13;
&#13;