任何证明微任务在渲染之前执行的例子?
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 来证明它。在省略我们不感兴趣的几个步骤的同时解释其当前状态:
-
- 选择要执行的任务
-
- 执行那个任务
-
- 执行微任务终点
-
- 更新渲染(如果需要的话)
-
- 重复
所以这里很清楚微任务是在渲染发生之前执行的。
还不信服?
这是一个片段,将仅使用微任务阻止您的 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
被渲染。
我看到几篇文章说渲染步骤在微任务之后。
我用这段代码测试它:
<!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 来证明它。在省略我们不感兴趣的几个步骤的同时解释其当前状态:
-
- 选择要执行的任务
-
- 执行那个任务
-
- 执行微任务终点
-
- 更新渲染(如果需要的话)
-
- 重复
所以这里很清楚微任务是在渲染发生之前执行的。
还不信服?
这是一个片段,将仅使用微任务阻止您的 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
被渲染。