html/javascript 中长时间运行的代码 [英] Long running code inside html/javascript

查看:30
本文介绍了html/javascript 中长时间运行的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我不能让它在服务器端运行,因为页面上会有 1000 次点击,这会导致来回通信过多.

解决方案

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

使用网络工作者(规范MDN) 这样计算就不会在主 UI 线程上运行.工作人员甚至可以将更新发布到主线程以显示进度.

<小时>

来自您对问题的评论:

<块引用>

它需要是同步操作,即点击...

这不符合,而且您确实希望它是同步的,如果它正在执行繁重的工作,您将锁定浏览器的 UI.

如果您需要在处理过程中防止进一步点击,只需在按钮运行时禁用该按钮即可.

这是一个计算 10 亿阶乘的示例(即使在现代浏览器上也需要一些时间),工作人员每百万更新一次:

HTML:

<div><div class="progress-wrapper"><div class="progress-bar"></div>

<div class="progress-counter">-</div>

<div class="result"></div>

CSS:

.progress-wrapper {边框:1px纯黑色;显示:内联块;宽度:70%;高度:1em;}.进度条 {显示:内联块;宽度:0;背景颜色:蓝色;高度:1em;}.进度计数器{显示:内联块;}

factorial_worker.js:

self.onmessage = function(e) {if (e.data && e.data.type === "start") {var n = 0,最大值 = 1000000000,结果 = 0;而 (n <最大值) {如果 (n % 1000000 === 0) {self.postMessage({type: "progress", progress: (n/max) * 100});}结果 += n;++n;}self.postMessage({type: "done", result: result});}};

页面中的主要脚本:

//获取workervar worker = new Worker("factorial_worker.js");//获取我们的各种元素var btn = document.querySelector(".the-btn");var progressBar = document.querySelector(".progress-bar");var progressCounter = document.querySelector(".progress-counter");var result = document.querySelector(".result");函数 setProgress(progress) {var 百分比 = progress.toFixed(2) + "%";console.log("进度:" + 百分比);progressCounter.innerHTML = 百分比;progressBar.style.width = 百分比;}//处理点击btn.addEventListener("点击", function() {//禁用按钮并告诉工作人员开始worker.postMessage({type: "start"});result.innerHTML = "工作中...";btn.disabled = true;});//处理来自worker的消息worker.onmessage = 函数(e){开关(e.data.type){案例进展":setProgress(e.data.progress);休息;案例完成"://重新启用按钮btn.disabled = false;设置进度(100);result.innerHTML = "结果:" + e.data.result;休息;}};

实时示例(使用一个技巧将 worker 嵌入页面,因为我们无法在 Stack Snippets 上处理外部文件):

//<忽略>忽略这一点,只是因为我们不能在 Stack Snippets 中有单独的文件var blob = new blob([document.querySelector(".the-worker").textContent], { type: "text/javascript" });//</忽略>//获取工人//在您自己的代码中,您将在此处引用 JavaScript 文件://var worker = new Worker("my_worker_script.js");var worker = new Worker(window.URL.createObjectURL(blob));//获取我们的各种元素var btn = document.querySelector(".the-btn");var progressBar = document.querySelector(".progress-bar");var progressCounter = document.querySelector(".progress-counter");var result = document.querySelector(".result");函数 setProgress(progress) {var 百分比 = progress.toFixed(2) + "%";progressCounter.innerHTML = 百分比;progressBar.style.width = 百分比;}//处理点击btn.addEventListener("点击", function() {//禁用按钮并告诉工作人员开始worker.postMessage({type: "start"});result.innerHTML = "工作中...";btn.disabled = true;});//处理来自worker的消息worker.onmessage = 函数(e){开关(e.data.type){案例进展":setProgress(e.data.progress);休息;案例完成"://重新启用按钮btn.disabled = false;设置进度(100);result.innerHTML = "结果:" + e.data.result;休息;}};

.progress-wrapper {边框:1px纯黑色;显示:内联块;宽度:70%;高度:1em;}.进度条 {显示:内联块;宽度:0;背景颜色:蓝色;高度:1em;}.进度计数器{显示:内联块;}

<div><div class="progress-wrapper"><div class="progress-bar"></div>

<div class="progress-counter"></div>

<div class="result"></div><script class="the-worker" type="javascript/worker">//这个脚本不会被JS引擎解析,因为它的类型是javascript/worker.self.onmessage = function(e) {if (e.data && e.data.type === "start") {var n = 0,最大值 = 1000000000,结果 = 0;而 (n <最大值) {如果 (n % 1000000 === 0) {self.postMessage({type: "progress", progress: (n/max) * 100});}结果 += n;++n;}self.postMessage({type: "done", result: result});}};</script>

I have a requirement to run an algorithm in a browser on button click. It very complex to code it in javascript and it would be very slow. Is there any recommended architecture for it ? Ideally I would like to code it in C++ or Python , but i guess it is not possible to run it inside a browser on button click. So, what are my next best options ?

I can't have it run on a serverside because there will be 1000s of clicks on the page which will result in too much communication back and forth.

解决方案

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>
    <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});
    }
};

Your main script in the page:

// 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;
    }
};

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 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>

这篇关于html/javascript 中长时间运行的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆