Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用setTimeout理解异步_Javascript - Fatal编程技术网

Javascript 使用setTimeout理解异步

Javascript 使用setTimeout理解异步,javascript,Javascript,我有一个UI,我需要动画平稳运行。每隔一段时间,我需要进行一次半大型数据计算,使动画跳过,直到计算完成 我试图通过使用setTimeout进行数据计算async来解决这个问题。类似于setTimeout(calcData(),0) 整个代码如下(简化): 但我还是在动画中跳过了。当我不需要做任何数据计算时,它运行平稳。我如何才能有效地做到这一点?谢谢 首先,让我们谈谈代码中发生了什么: while (animating) { performAnimation(); if (nee

我有一个UI,我需要动画平稳运行。每隔一段时间,我需要进行一次半大型数据计算,使动画跳过,直到计算完成

我试图通过使用
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);