Javascript DOM操作未按顺序执行

Javascript DOM操作未按顺序执行,javascript,dom,race-condition,flow-control,Javascript,Dom,Race Condition,Flow Control,我正在寻找一个解决方案,甚至只是在下面的例子中寻找一些“幕后”理论 DOM的操作似乎是以非阻塞方式进行的。换句话说,没有流控件等待DOM语句的执行 在本例中: 在onclick事件之后执行两条语句 将文本从左向右移动 document.getElementById('text').className = 'tr'; document.getElementById('text').className = 'tr'; 循环一段时间以停止执行 for(var i = 0,temp=1000000

我正在寻找一个解决方案,甚至只是在下面的例子中寻找一些“幕后”理论

DOM的操作似乎是以非阻塞方式进行的。换句话说,没有流控件等待DOM语句的执行

在本例中:

在onclick事件之后执行两条语句

  • 将文本从左向右移动

    document.getElementById('text').className = 'tr';
    
    document.getElementById('text').className = 'tr';
    
  • 循环一段时间以停止执行

    for(var i = 0,temp=1000000000; i<temp;i++){var dummy=0;} 
    
  • 循环一段时间以停止执行

    for(var i = 0,temp=1000000000; i<temp;i++){var dummy=0;}
    
  • 同样,如果在执行每个语句时流控制被阻塞,那么,正如预期的那样,文本将从左向右移动,然后在循环迭代时短暂暂停,然后文本从右向左移动

    相反,循环被执行,文本从左到右和从右到左的重新绘制永远不会发生。这说明了一种竞争条件

    但是,setTimeout()可以暂停执行足够长的时间,以使DOM语句能够完成任务并避免排队;没有办法知道每句话要花多长时间。如果间隔设置为短,则无法达到预期结果。如果将间隔设置为比需要的长,则性能会受到影响

    在DOM操作过程中,是否仍然可以在没有setTimeout()开销的情况下阻止执行?也许是某种回调例程

    如有任何见解,将不胜感激。谢谢

    不确定“setTimeout()的开销”是什么意思,但通常建议使用超时0调用setTimeout

    不确定“setTimeout()的开销”是什么意思,但通常建议使用超时为0的方式调用setTimeout


    如果只是几毫秒的分辨率,setTimeout也是绝对正确的方法

    您的循环正在阻止浏览器更新。
    此外,循环处理所需的时间也不可预测。对于智能JavaScript编译器来说,如果循环没有任何好处,那么由于优化,可以省略循环。

    setTimeout是绝对正确的方法,如果它只是几毫秒的分辨率

    您的循环正在阻止浏览器更新。
    此外,循环处理所需的时间也不可预测。关于智能JavaScript编译器,如果循环没有任何好处,那么由于优化,循环可以省略。

    我意识到这是一个老问题,但我想解释一下为什么循环会阻止文本向右更改

    浏览器以每秒60次的最大速率刷新窗口。这将通过事件循环完成,事件循环也会安排其他操作。首先,运行所有同步代码。然后,事件循环将经历延迟操作;包括影响窗口重绘的因素(例如,更改DOM元素中的类并应用样式)

    这就是这里发生的事情。触发事件时,将首先执行同步代码。即:

    1) 将
    tr
    作为类名分配给DOM元素数据(但不分配给显示的DOM本身。换句话说,如果在开发工具上检查元素,此时将看不到更改)

    2) 运行循环

    同步代码完成后,事件循环将查看还需要执行哪些操作。重新油漆将在这里进行。因此,此时您将看到dev工具上的元素获取
    tr
    类,文本向右移动

    此时安排要执行的操作的最佳方法是通过
    requestAnimationFrame
    (不一定是
    setTimeout
    )。因此:

    document.getElementById('text').className='tr';
    requestAnimationFrame(()=>{
    // ...
    } );
    
    我已经更改了您的代码,以便更好地说明我所说的内容:

    document.addEventListener('mousedown',shift\u text,false);
    函数shift_text(){
    requestAnimationFrame(()=>{
    console.log('requestAnimationFrame 1')
    } );
    //先执行后停止
    document.getElementById('text')。className='tr';
    log('className now is',document.getElementById('text').className);
    requestAnimationFrame(()=>{
    console.log('requestAnimationFrame 2')
    } );
    //大圈停车
    
    对于(var i=0,temp=3000000000;i我意识到这是一个老问题,但我想解释一下为什么循环会停止文本向右的更改

    浏览器以每秒60次的最大速率刷新窗口。这将通过事件循环完成,该循环还计划其他操作。首先,运行所有同步代码。然后,事件循环将执行延迟操作;包括影响窗口重新绘制的操作(例如,更改DOM元素中的类并应用样式)

    这就是此处发生的情况。触发事件时,将首先执行同步代码。即:

    1) 将
    tr
    作为类名分配给DOM元素数据(但不分配给显示的DOM本身。换句话说,如果在开发工具上检查元素,此时将看不到更改)

    2) 运行循环

    同步代码完成后,事件循环将看到还需要做什么。重新绘制将在此处进行。因此,此时您将看到开发工具上的元素获取
    tr
    类,文本向右移动

    安排此时要执行的操作的最佳方法是通过
    requestAnimationFrame
    (不一定是
    setTimeout
    )。因此:

    document.getElementById('text').className='tr';
    requestAnimationFrame(()=>{
    // ...
    } );
    
    我已经更改了您的代码,以便更好地说明我所说的内容:

    document.addEventLis
    
    document.getElementById('text').className = 'tl';
    
    class name now is tr // Despite the text still being on the left.
    sync code is done // After a while due to the large loop.
    requestAnimationFrame 1 // At this point, the text will be on the right.
    requestAnimationFrame 2