在async函数中加载脚本导致display_page无法执行的问题
问题分析与修复:await load_scripts后display_page无法执行的问题
你遇到的核心问题:在异步函数f1中,给load_scripts()加await时,后续的display_page()完全不执行;但去掉await的话,display_page()会执行,却无法满足「脚本加载完成后再显示页面」的需求。
你的代码如下:
const loading = document.getElementById('loading_screen') const page = document.getElementById('main') function hide_page() { console.log('1') loading.style.display = 'block' loading.style.opacity = '1' loading.addEventListener('transitionend', () => { page.style.display = 'none' }) return new Promise((resolve) => { loading.ontransitionend = resolve }) } function display_page() { console.log('2') page.style.display = 'flex' loading.style.opacity = '0' loading.addEventListener('transitionend', () => { loading.style.display = 'none' }) return new Promise((resolve) => { loading.ontransitionend = resolve }) } function load_scripts(files) { var promises = [] files.forEach((src) => { let script = document.createElement("script") script.setAttribute('type', 'text/javascript') script.setAttribute('class', 'local_script') script.async = false; script.setAttribute('src', src) document.getElementById('head').appendChild(script) promises.push(new Promise((resolve) => { script.onload = resolve script.onerror = resolve })); }) return Promise.all(promises) } async function f1() { await hide_page() await load_scripts(some_scripts_urls); // load_scripts(some_scripts_urls); //此方式可执行display_page,但脚本会后执行,不符合需求 await display_page(); console.log('3') } f1()
问题根源
load_scripts的Promise可能永久pending
设置script.async = false后,脚本按顺序同步加载,但如果脚本URL错误、存在跨域问题,或者浏览器缓存导致onload/onerror事件不触发,对应的Promise就永远不会resolve,导致await load_scripts卡住,后续代码无法执行。过渡事件绑定逻辑冲突
hide_page和display_page同时使用addEventListener和ontransitionend赋值(后者会覆盖前者的事件处理函数),且未移除监听,可能导致过渡事件触发逻辑混乱,影响Promise的resolve。
修复方案
1. 修复load_scripts的Promise触发逻辑
兼容所有加载场景,确保每个脚本的Promise都能正常resolve:
function load_scripts(files) { var promises = [] files.forEach((src) => { promises.push(new Promise((resolve) => { let script = document.createElement("script") script.type = 'text/javascript' script.className = 'local_script' script.async = false; script.src = src // 统一处理加载完成/失败的逻辑 const finish = () => { // 移除事件监听避免重复触发 script.onload = null script.onerror = null script.onreadystatechange = null resolve() } script.onload = finish script.onerror = finish // 兼容IE等老浏览器的状态变化 script.onreadystatechange = () => { if (['loaded', 'complete'].includes(script.readyState)) { finish() } } document.getElementById('head').appendChild(script) })); }) return Promise.all(promises) }
2. 修复过渡事件处理逻辑
确保过渡事件只触发一次,且Promise能正确resolve:
function hide_page() { console.log('1') // 重置状态+触发重绘,确保过渡能正常触发 loading.style.display = 'none' loading.offsetHeight // 强制浏览器重绘,识别状态变化 loading.style.display = 'block' loading.style.opacity = '1' return new Promise((resolve) => { const onTransitionEnd = (e) => { // 确保只监听opacity的过渡结束事件 if (e.propertyName === 'opacity') { page.style.display = 'none' loading.removeEventListener('transitionend', onTransitionEnd) resolve() } } loading.addEventListener('transitionend', onTransitionEnd) }) } function display_page() { console.log('2') page.style.display = 'flex' // 重置loading状态+触发重绘 loading.style.display = 'block' loading.offsetHeight loading.style.opacity = '0' return new Promise((resolve) => { const onTransitionEnd = (e) => { if (e.propertyName === 'opacity') { loading.style.display = 'none' loading.removeEventListener('transitionend', onTransitionEnd) resolve() } } loading.addEventListener('transitionend', onTransitionEnd) }) }
3. 优化f1函数的容错性
添加错误捕获,避免脚本加载失败导致整个流程卡住:
async function f1() { await hide_page() try { await load_scripts(some_scripts_urls); } catch (err) { console.error('脚本加载失败:', err) } await display_page(); console.log('3') } f1()
内容的提问来源于stack exchange,提问作者Giovanni5454
相关产品推荐
相关产品推荐

