else代码块异步函数执行顺序问题:如何先替换加载按钮再执行业务逻辑
核心原因
浏览器的DOM样式更新和页面重绘属于宏任务,会在当前调用栈的所有同步代码、微任务全部执行完成后才会触发。你修改DOM样式后,后续生成PDF、发送请求的逻辑会阻塞重绘流程,导致按钮状态变化要等所有业务逻辑执行完才会展示。
你之前的Promise改造无效,是因为Promise构造函数的执行器是同步运行的,resolve(replaceButtons())会立刻执行按钮替换逻辑,而then回调属于微任务,优先级高于DOM重绘的宏任务,依然会阻塞渲染流程。
解决方案
方案1:使用setTimeout(最简实现)
将后续业务逻辑用setTimeout包裹,延迟设为0即可,这样业务逻辑会被推入下一个宏任务队列,浏览器会先完成DOM重绘再执行业务代码。
改造后的else分支代码如下:
else { replaceButtons() // 让出线程给浏览器完成DOM重绘 setTimeout(() => { let pdf = new jsPDF('p', 'mm', [297, 210], true); pdf.text(10, 280, 'Foo'); pdf.text(10, 285, 'Bar'); let blob = pdf.output('blob'); const formData = new FormData(); formData.append('file', blob); $.ajax('http://localhost:8080/test', { method: 'POST', data: formData, processData: false, contentType: false, }); fetch('http://localhost:8080/test', { method: "POST" }) .then(function(response) { alert('Success')}) }, 0) }
方案2:requestAnimationFrame + Promise(更稳妥)
如果对渲染时机要求更高,可以用该方案确保重绘完成后再执行业务逻辑:
else { replaceButtons() // requestAnimationFrame会在页面重绘前触发 requestAnimationFrame(() => { // 嵌套一层Promise微任务,确保重绘完成后再执行业务逻辑 Promise.resolve().then(() => { // 后续业务逻辑写在这里 let pdf = new jsPDF('p', 'mm', [297, 210], true); // 剩余代码省略 }) }) }
内容的提问来源于stack exchange,提问作者Katharina Schreiber
相关产品推荐
相关产品推荐

