Javascript 使用setTimeout理解异步
我有一个UI,我需要动画平稳运行。每隔一段时间,我需要进行一次半大型数据计算,使动画跳过,直到计算完成 我试图通过使用Javascript 使用setTimeout理解异步,javascript,Javascript,我有一个UI,我需要动画平稳运行。每隔一段时间,我需要进行一次半大型数据计算,使动画跳过,直到计算完成 我试图通过使用setTimeout进行数据计算async来解决这个问题。类似于setTimeout(calcData(),0) 整个代码如下(简化): 但我还是在动画中跳过了。当我不需要做任何数据计算时,它运行平稳。我如何才能有效地做到这一点?谢谢 首先,让我们谈谈代码中发生了什么: while (animating) { performAnimation(); if (nee
setTimeout
进行数据计算async来解决这个问题。类似于setTimeout(calcData(),0)代码>
整个代码如下(简化):
但我还是在动画中跳过了。当我不需要做任何数据计算时,它运行平稳。我如何才能有效地做到这一点?谢谢 首先,让我们谈谈代码中发生了什么:
while (animating) {
performAnimation();
if (needCalc) {
// it should be setTimeout(calcData, 0);
setTimeout(calcData(), 0);
}
}
第行setTimeout(calcData(),0)
实际上,您不会延迟调用calcData
函数,而是调用它,因为在函数名之后使用了()
操作符
其次,让我们思考一下,当您在上面的代码中真正延迟调用calcData
时会发生什么:通常JavaScript在一个线程中运行,因此,如果您有这样的代码:
setTimeout(doSomething, 0);
while (true) {};
doSomething
将永远不会被调用,因为javascript的解释器执行,而将永远循环,并且它没有“空闲时间”执行其他事情(甚至UI)setTimeout
-只需在解释器空闲时安排执行doSomething
,就可以执行此功能
所以,当浏览器执行javascript函数时,所有其他内容都会冻结
解决方案:
如果您有需要处理的大数据,可能最好在后端进行计算,然后将结果发送到前端
通常,当您需要进行一些计算并呈现结果时,最好使用而不是循环。浏览器将尽快执行传入requestAnimationFrame
的函数,但您也会给浏览器一段时间来处理其他事件。您可以使用的requestAnimationFrame
for(逐步教程)看到平滑重画
若你们真的想在前端处理大量的数据,并且你们想让ui工作顺畅,你们可以尝试使用。WebWorker看起来像JavaScript中的线程,您需要通过在主UI“线程”和WebWorker之间传递消息来进行通信,WebWorker上的计算不会影响UI线程
您会看到跳过,因为一次只运行一个javascript线程。当异步完成某项任务时,javascript引擎会将其放入稍后运行的队列,然后查找其他要执行的任务。当队列中的某个操作需要完成时,引擎将把它拉出并执行它,阻塞所有其他操作,直到它完成。然后引擎将从其队列中拉出其他操作来执行
因此,如果要使渲染平稳运行,必须将计算分解为多个异步调用,以便引擎在计算之间安排渲染操作。如果您只是在数组上迭代,这很容易实现,因此您可以执行以下操作:
var now=Date.now;
if(window.performance&&performance.now){//use performace.now if we can
now=performance.now;
}
function calculate(){
var batchSize=10;//If you have a exceptionally long operation you may want to make this lower.
var i=0;
var next=function(){
var start=now();
while(now()-start<14){//14ms / frame
var end=Math.min(i+batchSize,data.length);
for(;i<end;i++){//do batches to reduce time overhead
do_calc(data[i]);
}
}
if(i<data.length) setTimeout(next,1)//defer to next tick
};
next();
}
calculate();
function render(){
do_render_stuff();
if(animating) {
requestAnimationFrame(render);//use requestAnimationFrame rather then setTimeout for rendering
}
}
render();
var now=Date.now;
if(window.performance&&performance.now){//如果可以,请使用performace.now
现在=性能。现在;
}
函数计算(){
var batchSize=10;//如果您有一个非常长的操作,您可能希望将其降低。
var i=0;
var next=函数(){
var start=now();
虽然(now()-start大多数情况下,您的问题归结为setTimeout()的错误使用
setTimeout的第一个参数是对要调用的函数的引用。在代码中,您不是在引用calcData函数,而是在调用它,因为函数名后面包含了()
其次,您为延迟设置了0并不意味着您在函数运行之前将有0秒的延迟。JavaScript在单线程上下文中运行。setTimeout函数放置在队列中,并在JavaScript引擎可用时执行,但最短不超过10毫秒或您指定的量(以较小者为准)
事实上,你的路线应该是:
setTimeout(calcData(),10);
我对JavaScript有点生疏,但我觉得没有足够的信息。好吧。我想我只需要知道这是否是正确的方法。我确定这不是一个独特的问题,在保持动画/用户界面平滑的同时必须进行大量计算。啊,那么我想这只是你的英语。请你在跳过时澄清一下,好吗?我知道我现在觉得自己很笨,但我只是不明白我有一个平滑的动画,直到我需要调用calcData(),它会停止动画,然后在calcData完成后重新启动。动画是什么?你能使用动画gif吗?
setTimeout(calcData(), 0);
setTimeout(calcData(),10);