任何证明微任务在渲染之前执行的例子?

Any example proving microtask is executed before rendering?

我看到几篇文章说渲染步骤在微任务之后。

我用这段代码测试它:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <p>test</p>
  <script>
const p = document.querySelector('p');
p.textContent = 'text';
Promise.resolve().then(function microtask() {
  debugger;
  p.textContent = 'Promise';
});
  </script>
</body>
</html>

此代码似乎显示 UI 在微任务 运行.

之前 重新呈现

我是不是想错了?有没有什么好的例子表明渲染是在微任务之后 运行 ?

你可以简单地通过查看 event-loop processing model 来证明它。在省略我们不感兴趣的几个步骤的同时解释其当前状态:

    1. 选择要执行的任务
    1. 执行那个任务
    1. 执行微任务终点
    1. 更新渲染(如果需要的话)
    1. 重复

所以这里很清楚微任务是在渲染发生之前执行的。

还不信服?

这是一个片段,将仅使用微任务阻止您的 UI 5 秒。释放此锁之前不会渲染页面内容:

// We wrap our code in a 0 timeout and two rAF levels
// to be sure the initial rendering of the page did occur
setTimeout( () => {
requestAnimationFrame( () => {
  requestAnimationFrame( () => {

    // Now we modify the DOM
    document.querySelector( 'p' ).textContent = "modified";
    // and we start locking the UI using a Promise chain
    const start = performance.now();
    (function lockUI() {     // IIFE
      if( performance.now() - start  < 5000 ) {
        // recursive Promise chaining
        // all these promises will get executed before the next rendering
        // and block the UI rendering
        // even though we were in an rAF callback!
        return Promise.resolve()
          .then( lockUI );
      }
    } )();
    
  } );
} );
}, 0 );
<p>Initial (please wait 5s)</p>

细心的读者会注意到,这个脚本甚至没有将微任务排队到事件循环的第 7 步,而是排队到 11.12 交错微任务检查点.

这只会更好地证明实际渲染只在步骤 11.15 完成,之前的任何事情实际上都可以延迟它。


所以在你的测试用例中,“文本”永远不应该呈现,因为通过调用Promise.resolve().then()你实际上排队了一个微任务,从事件循环的角度视图实际上与这里的同步操作相同,因为在排队之后没有任何事情发生。
除了 有一种情况 你仍然可以看到呈现的文本,如果浏览器进入 spin the event loop 算法。如果浏览器面临一个长任务并决定它可以执行这个算法,这可能会发生这种情况,这将允许渲染步骤发生,即使仍然有一个长任务 运行.
例如,每当您启动 alert()prompt() 等模式时,Firefox 都会执行此操作

所以在Firefox中,这段代码实际上会渲染文本text,Chrome这里没有调用这个算法,所以不会渲染任何东西,甚至不渲染初始的 test:

const p = document.querySelector('p');
p.textContent = 'text';
Promise.resolve().then(function microtask() {
  alert();
  p.textContent = 'Promise';
});
<p>test</p>

但是 Chrome 会用 debugger 调用此算法。所以这个关键字不会阻止渲染,这就是为什么你看到 text 被渲染。