Google Chrome 并不总是在添加到 Macrotask 队列的任务之间呈现(使用 setTimeout)

问题描述 投票:0回答:0

我认为 Javascript 事件循环旨在跨 Web 浏览器以类似的方式执行 Macrotask 队列中的任务。简而言之(不考虑评估脚本、微任务队列等):

  1. 从 Macrotask 队列中取出最旧的任务并运行它

  2. 渲染

  3. 重复

我在 Chrome 中面临不一致,而 Firefox 在遵循上述步骤时似乎更加一致。

例子

这里是 >silly< code example 来证明这个问题:

index.html

...
<head>
<script src="index.js" defer></script>
</head>
...

index.js

"use strict";

function sleep(ms)
{
    const start = performance.now();
    while ((performance.now() - start) < ms);
}

function doNextPart()
{
    currentPart++;
    sleep(20);
    addToRender(currentPart.toString());
}

function addToRender(part)
{
    partsList.push(part);
}

function render(timestamp)
{
    frame++;
    console.log(`frame: ${frame} \t rendering time: ${timestamp}`);

    for (const part of partsList)
    {
        const itemDiv = document.createElement("div");
        itemDiv.innerHTML = `part: ${part} || frame: ${frame}, ${timestamp}`;
        partsContainerDiv.appendChild(itemDiv);
    }

    document.body.appendChild(partsContainerDiv);

    partsList.length = 0;
    if (frame <= 5)
    {
        window.requestAnimationFrame(render);
    }
}

const partsContainerDiv = document.createElement("div");
const partsList = [];
let frame = 0;
let currentPart = 0;

window.requestAnimationFrame(render);

setTimeout(doNextPart);
setTimeout(doNextPart);
setTimeout(doNextPart);

这里有一些解释

  • requestAnimationFrame()
    用于渲染:
    partsList
    数组中当前有什么然后清除该数组,当前
    frame
    数,
    timestamp
  • doNexPart()
    函数:只是使用sleep()函数在给定时间内阻塞
    事件循环
    ,然后将“结果”(
    currentPart
    )添加到
    partsList
    数组进行渲染
  • 循环在 5 帧后停止
  • 它在
    宏任务队列
    中添加了doNextPart()函数三次
  • (
    console.log()
    用于记录所有 (5) 帧 - 主要用于最后一帧时间戳,没有来自 Macrotask 队列的任务 )

这就是我期待的

  • Macrotask 队列中获取任务 => 首先运行

    doNextPart()
    ,它将“1”作为“结果”添加到
    partsList
    数组

  • render => 事件循环现在可以调用

    render()
    函数进行渲染,所以 HTML 输出是

    part: 1 || frame: 1

  • 重复

火狐

我希望最终的 HTML 输出应该是这样的:

part: 1 || frame: 1 

part: 2 || frame: 2 

part: 3 || frame: 3

  • 以上是我在Firefox几乎一直得到的。

  • 前三帧每帧花费大约25ms

    sleep(20ms)
    ,另外两帧花费大约8ms(总共5帧)。

换句话说 - 它在任务之间呈现,因为它试图以通常由显示刷新率给出的比率呈现(假设每个 8ms 对于 120Hz) - 换句话说 Firefox 试图遵循步骤。

但是Chrome的HTML输出是:

part: 1 || frame: 2

part: 2 || frame: 2

part: 3 || frame: 2

所以它在 一帧 中同时渲染,那一帧花了 91.7 毫秒

当我查看“性能”选项卡时,任务按应有的方式执行,但绘制仅在最后一个之后完成。

但是当传递给

sleep()
函数的时间足够高100ms对我有用)Chrome按预期呈现

------------------------------------------------ ---------------------------------------------- ------

Chrome 版本测试:110.0.5481.178

Firefox 测试版本:110.0.1

主要来源:

探索 ES6

JavaScript 可视化工具

------------------------------------------------ ---------------------------------------------- ------

问题

我追求的是:

  • 我在这里做错了什么吗
  • 这种行为是正常的还是一种错误
  • 我们是否应该期望在处理宏任务队列的浏览器中有相同的行为

谢谢

javascript google-chrome settimeout requestanimationframe
© www.soinside.com 2019 - 2024. All rights reserved.