以下是用JavaScript编写需要在浏览器上运行的长计算的正确方法吗?

以下是用JavaScript编写需要在浏览器上运行的长计算的正确方法吗?,javascript,async-await,es6-promise,ecmascript-2017,Javascript,Async Await,Es6 Promise,Ecmascript 2017,我正在尝试使用async/await在浏览器上对JavaScript进行长时间计算。是否应该更改代码或进行任何改进?使用承诺似乎会让事情变得复杂。在问题的最后,我还有两个相关的问题 它正在做60000(阶乘),并且答案太长,无法在屏幕上显示,因此将以二进制显示答案的位数。(以十进制显示答案的位数对于转换来说花费的时间太长) 迭代版本为: (请注意:计算要到3秒钟后才会开始,以显示没有计算时UI的外观) (函数(){ 让startTimeOfProgram=performance.now(),

我正在尝试使用async/await在浏览器上对JavaScript进行长时间计算。是否应该更改代码或进行任何改进?使用承诺似乎会让事情变得复杂。在问题的最后,我还有两个相关的问题

它正在做
60000(阶乘),并且答案太长,无法在屏幕上显示,因此将以二进制显示答案的位数。(以十进制显示答案的位数对于转换来说花费的时间太长)

迭代版本为:

(请注意:计算要到3秒钟后才会开始,以显示没有计算时UI的外观)

(函数(){
让startTimeOfProgram=performance.now(),
计时器=3,
元素=$(“#状态显示内容”),
元素计时器=$(“#计时器”);
setInterval(()=>{elementTimer.html((Math.round((performance.now()-startTimeOfProgram)/10)/100).toFixed(2))},33);
函数updateState(){
html(timer--).css({transition:'none}).css({opacity:1});
如果(计时器<0)计时器=3;
//需要是下一个周期,因为无法更改
//过渡并在同一个循环中设置动画
setTimeout(函数(){
css({transition:“opacity 1s”}).css({opacity:0}).on(“transitionend”,()=>{updateState();element.off(“transitionend”);});
}, 0);
}
不动产();
函数二进制长度(n){
返回n.toString(2).长度;
}
const occasionalSleeper=(函数(){
让lastSleepingTime=performance.now();
返回函数(){
如果(performance.now()-lastSleepingTime>33){
lastSleepingTime=performance.now();
返回新承诺(resolve=>setTimeout(resolve,0));
}否则{
返回承诺。解决();
}
}
}());
异步函数asyncBigIntFactorial(n){
让start=performance.now();
n=BigInt(n);

如果(n如评论中所述,对于持久的计算,您可以使用Web Workers。这样您可以保持浏览器的交互式,而不必定期引入
setTimeout
“跃点”

为了尽可能方便地使用web workers,我建议使用以下通用“插件”代码,这是我在前面的:

现在,您可以让web worker使用以下语法执行任何纯函数:

myPureAdditionFunction.callAsWorker(null, 1, 2)
                      .then((sum) => console.log("1+2=" + sum)); 
如前所述,这消除了使用类似
occasionsleeper()
的东西注入执行的需要

您的核心功能可以是:

function bigIntFactorial(n) {
    n = BigInt(n);
    let result = 1n;
    for (let i = 2n; i <= n; i++) result *= i;
    return result;
}
我修改了您的代码片段以使用此方法。我还删除了3秒的运行时间,因为对于web worker,您不必担心DOM和绘制事件

让startTimeOfProgram=performance.now(),
计时器=3,
元素=$(“#状态显示内容”),
元素计时器=$(“#计时器”);
让秒表=设定间隔(()=>{
html((Math.round((performance.now()-startTimeOfProgram)/10)/100.toFixed(2))
}, 33);
函数updateState(){
html(计时器--).css({transition:“none”})
.css({opacity:1});
如果(计时器<0)计时器=3;
//需要是下一个周期,因为无法更改
//过渡并在同一个循环中设置动画
setTimeout(函数(){
css({transition:“opacity 1s”})
.css({opacity:0})
.on(“transitionend”,()=>{
if(秒表)更新属性();
元素。关闭(“转换”);
});
});
}
不动产();
const binaryLength=n=>n.toString(2).length;
Function.prototype.callAsWorker=函数(…args){
返回新承诺((解决、拒绝)=>{
const code=`self.onmessage=e=>self.postMessage((${this}).call(…e.data));`,
blob=newblob([code],{type:“text/javascript”}),
worker=新的worker(window.URL.createObjectURL(blob));
worker.onmessage=e=>(解析(e.data),worker.terminate());
worker.onerror=e=>(拒绝(e.message),worker.terminate();
worker.postMessage(args);
});
}
函数bigint阶乘(n){
n=BigInt(n);
设结果=1n;
对于(设i=2n;i{
间隔时间(秒表);
秒表=零;
$(“#计算结果”)
.html(`二进制答案的位数:${binaryLength(result)}
所用时间:${Math.round((performance.now()-startTimeOfProgram)/10)/100}秒`); });
#状态显示{
背景色:#000;
颜色:绿色;
字体:111px Arial,无衬线;
宽度:150px;
高度:150像素;
边界半径:21%;
文本对齐:居中;
线高:150px;
}
#计时器{
宽度:150px;
文本对齐:居中;
字体:15px Arial,无衬线;
}
#状态显示内容{
过渡:不透明度1s
}
#计算结果{
左边缘:.3em;
}
#左面板,#计算结果{
显示:内联块;
}


鉴于您有可用的代码,并且正在寻求改进/批评,我建议您继续提问。这些都是专门针对您的问题设计的。您可能希望调查Web Workers。这是否回答了您的问题?
function bigIntFactorial(n) {
    n = BigInt(n);
    let result = 1n;
    for (let i = 2n; i <= n; i++) result *= i;
    return result;
}
bigIntFactorial.callAsWorker(null, 60000).then(/* handler */);