WebView2应用调用JavaScript的async/await时出现冻结问题求助
问题概述
基于Microsoft WebView2的嵌入式Web应用,在执行含await的showModalDialog polyfill代码时,整个应用完全冻结,无法响应任何输入;但相同代码在Edge/Chrome浏览器中运行正常。使用的polyfill基于MDN提供的实现,测试代码通过await调用该polyfill获取模态框返回值。
核心原因
WebView2的渲染线程与宿主应用的UI主线程存在绑定关系,原生<dialog>的showModal()方法在WebView2环境中会触发特殊的模态阻塞逻辑——不同于普通浏览器仅阻塞页面内的JS执行,WebView2会将这种阻塞传导至宿主应用的主线程,导致整个应用失去响应。而浏览器环境中,<dialog>的模态仅限制页面内交互,不会影响浏览器本身的消息循环。
修复方案
方案1:替换原生<dialog>为自定义模态实现
放弃使用原生<dialog>元素,改用CSS实现模态遮罩,配合异步逻辑实现相同功能,避免触发WebView2的主线程阻塞:
修改后的polyfill代码:
window.showModalDialog = window.showModalDialog || function(url, arg, opt) { url = url || ''; arg = arg || null; opt = opt || 'dialogWidth:300px;dialogHeight:200px'; // 解析模态框样式参数 const styleObj = {}; opt.split(';').forEach(item => { const [key, val] = item.trim().split(':'); if (key && val) { styleObj[key.replace(/dialog/gi, '')] = val; } }); // 创建全屏模态遮罩 const overlay = document.createElement('div'); overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 9999; `; // 创建模态框容器 const dialogContainer = document.createElement('div'); Object.keys(styleObj).forEach(key => { dialogContainer.style[key] = styleObj[key]; }); dialogContainer.style.cssText += ` position: relative; background: white; border-radius: 4px; overflow: hidden; `; // 插入关闭按钮与iframe内容 dialogContainer.innerHTML = ` <a href="#" id="dialog-close" style="position: absolute; top: 0; right: 5px; font-size: 20px; color: #000; text-decoration: none; outline: none; padding: 5px;">×</a> <iframe id="dialog-body" src="${url}" style="border: 0; width: 100%; height: 100%;"></iframe> `; overlay.appendChild(dialogContainer); document.body.appendChild(overlay); const iframe = document.getElementById('dialog-body'); iframe.contentWindow.dialogArguments = arg; // 封装关闭逻辑 return new Promise((resolve) => { const closeHandler = () => { overlay.remove(); resolve(iframe.contentWindow.returnValue); }; // 绑定关闭按钮事件 document.getElementById('dialog-close').addEventListener('click', e => { e.preventDefault(); closeHandler(); }); // 支持iframe内部主动关闭模态框(可选) iframe.contentWindow.addEventListener('message', (e) => { if (e.data === 'closeModal') { closeHandler(); } }); }); };
方案2:升级WebView2 Runtime至最新版本
部分旧版本WebView2存在<dialog>元素的模态阻塞bug,升级到最新稳定版可解决该问题。可通过宿主应用自动更新WebView2 Runtime,或引导用户手动安装。
方案3:调整宿主应用的消息循环处理
确保宿主应用的主线程消息循环不会被WebView2的回调阻塞,避免在同步回调中执行耗时操作,保证UI线程能及时处理用户输入事件。
测试验证
使用修改后的polyfill代码,测试await window.showModalDialog(...)逻辑,应用将不再冻结,模态框可正常交互,关闭后能正确获取返回值。
内容的提问来源于stack exchange,提问作者RISHAB

