javascript - html/javascript 中长时间运行的代码

标签 javascript web

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

我无法让它在服务器端运行,因为页面上会有数千次点击,这将导致过多的来回通信。

最佳答案

So, what are my next best options

使用 Web Worker( specificationMDN ),以便计算不在主 UI 线程上运行。工作人员甚至可以将更新发布到主线程以显示进度。


根据您对问题的评论:

It needs to be synchronous operation i.e on click...

这并不符合,并且您真的希望它是同步的,如果它正在做繁重的工作,您将锁定浏览器的 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;
    }
};
.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;
}
<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>

关于javascript - html/javascript 中长时间运行的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46346297/

相关文章:

python - 有没有办法用 Python 控制窗口?

javascript - oninput JavaScript 日期函数计算器

PHP imagick - 压缩上的白色方 block

java - 通过移动设备访问 Java Web 应用程序

firefox - Mozilla Firefox 实现状态页面

javascript - 你能用c++加载一个网页,包括JS和动态html并获取渲染的DOM字符串吗?

javascript - 使用indexedDB返回 'undefined'

javascript - 从服务调用组件函数 - 可能的循环依赖 - Angular

Javascript 标记化列表到关联集合

javascript - foo in bar - 'in' 运算符 javascript?