javascript 事件循环中宏任务与微任务通过阻塞主线程来影响触摸响应,若在主线程执行大量同步代码或积压微任务,会导致触摸事件(如 touchstart、touchend)的回调被推迟处理,造成页面卡顿。要确保触摸响应及时,应避免在主线程进行耗时计算,并将非关键逻辑放入 settimeout 等宏任务中,让出主线程给 ui 渲染和事件处理。

如何验证微任务积压对触摸事件的延迟
可以通过在触摸事件中触发大量微任务来模拟主线程阻塞,观察后续触摸事件的响应时间。具体做法是在 touchstart 处理器中创建一个 Promise 链或 MutationObserver 队列,强制浏览器先处理完所有微任务再调度下一个宏任务或事件。

// 模拟微任务积压的代码
const btn = document.getElementById('btn');
let count = 0;
btn.addEventListener('touchstart', (e) => {
console.log('Touch Start:', Date.now());
// 创建大量微任务
for (let i = 0; i {
count++;
});
}
});
// 预期结果:
// 1. 'Touch Start' 立即打印
// 2. 随后控制台可能因微任务执行产生大量日志(如果未优化)
// 3. 后续的 touchmove 或 touchend 事件会被推迟到当前宏任务(即当前点击处理函数)结束后,且微任务清空后才会被调度
宏任务队列如何决定触摸响应的优先级
宏任务(如 setTimeout、setInterval、I/O 回调)在事件循环中按顺序执行,每个宏任务执行完后会检查并执行所有微任务。触摸事件本身通常作为宏任务入队,因此如果前面有耗时的宏任务(如大型 DOM 操作或复杂计算),触摸事件的响应就会滞后。通过将非关键逻辑移至宏任务,可以确保触摸事件能及时被处理。

// 对比宏任务与同步代码对触摸的影响
const btn = document.getElementById('btn');
// 场景1:同步阻塞
btn.addEventListener('touchstart', () => {
console.log('Sync Block Start');
let start = Date.now();
while (Date.now() - start {
console.log('Async Block Start');
setTimeout(() => {
let start = Date.now();
while (Date.now() - start <h2>基于Promise微任务队列的具体问题</h2><p>在程序中,如果触摸事件处理器内部调用了多个 <code>Promise.then()</code>,这些回调会进入微任务队列。根据 JavaScript 事件循环规则,当前宏任务(即触摸事件处理函数)结束后,引擎会清空整个微任务队列,然后才去处理下一个宏任务(如下一个触摸事件或渲染帧)。这意味着,如果在触摸事件中嵌套了深层的 Promise 链,后续的触摸交互会被显著延迟,直到所有微任务执行完毕。</p>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











