html2canvas 1.4.1 在 iOS Safari 中生成图片卡住的问题排查与修复

html2canvas 1.4.1 在 iOS Safari 中生成图片卡住的问题排查与修复

问题现象

在 iOS Safari / 移动端 vConsole 环境中,使用 html2canvas 1.4.1 时无法成功生成图片。

最初看到的报错类似:

text 复制代码
TypeError: undefined is not a function

(near '...t.match(...)...')

同时 html2canvas 日志停在:

text 复制代码
Starting document clone...

之后没有进入 resolved,也没有正常输出 canvas。

最小复现

为了判断是脚本问题还是业务 DOM 问题,先做了一个最小 DOM 测试:

js 复制代码
function testHtml2canvasCore(scriptUrl) {

    scriptUrl = scriptUrl || "https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js";

  


    $.getScript(scriptUrl + "?v=iframefix").done(function () {

        var demo = document.createElement("div");

        demo.id = "html2canvasCoreDemo";

        demo.style.cssText = [

            "position:fixed",

            "left:10px",

            "top:10px",

            "width:120px",

            "height:60px",

            "background:#fff",

            "color:#111",

            "font-size:14px",

            "z-index:999999"

        ].join(";");

        demo.innerHTML = "core demo";

        document.body.appendChild(demo);

  


        html2canvas(demo, {

            scale: 1,

            useCORS: true,

            logging: true

        }).then(function (canvas) {

            console.log("core demo ok", canvas.width, canvas.height);

        }).catch(function (err) {

            console.error("core demo error", err);

        });

    });

}

测试结果:

  • 使用 1.4.1:最小 DOM 也卡住。

这说明问题第一层不在业务 DOM,而在 html2canvas 1.4.1 自身的 document clone / iframe 流程。

根因定位

html2canvas 1.4.1 在生成图片前会 clone 当前 document 到一个隐藏 iframe 中,然后等待 iframe 加载完成。

相关的 minified 代码原本类似:

js 复制代码
In=function(B){

    return new Promise(function(e,A){

        var t=B.contentWindow;

        if(!t)return A("No window assigned for iframe");

        var r=t.document;

        t.onload=B.onload=function(){

            t.onload=B.onload=null;

            var A=setInterval(function(){

                0<r.body.childNodes.length&&"complete"===r.readyState&&(clearInterval(A),e(B))

            },50)

        }

    })

}

关键问题在这里:

js 复制代码
t.onload = B.onload = function () { ... }

原逻辑必须等 iframe 的 load 事件触发后,才开始轮询 iframe document 是否准备好。

在当前 iOS Safari 环境中,这个隐藏 iframe 的 load 事件没有稳定触发,导致 Promise 一直不 resolve,于是 html2canvas 日志停在:

text 复制代码
Starting document clone...

这也是为什么业务 DOM 和极简 DOM 都失败。

修复方案

修复思路是:不要完全依赖 iframe 的 load 事件。注册 onload 的同时,立即启动一次相同的检查逻辑。

补丁后的 In 函数:

js 复制代码
In=function(B){

    return new Promise(function(e,A){

        var t=B.contentWindow;

        if(!t)return A("No window assigned for iframe");

        var r=t.document,n=function(){

            t.onload=B.onload=null;

            var A=setInterval(function(){

                r.body&&0<r.body.childNodes.length&&("complete"===r.readyState||"interactive"===r.readyState)&&(clearInterval(A),e(B))

            },50)

        };

        t.onload=B.onload=n,setTimeout(n,0)

    })

}

相比原逻辑,改动点有三个:

  1. 把 onload 回调提取成 n。

  2. 保留原来的 t.onload = B.onload = n。

  3. 增加 setTimeout(n, 0),避免 iframe load 事件不触发时永久卡住。

同时轮询条件也做了兼容:

js 复制代码
r.body &&

0 < r.body.childNodes.length &&

("complete" === r.readyState || "interactive" === r.readyState)

这样 iframe document 已经进入 interactive 状态时也可以继续。

验证方式

在移动端 vConsole 中验证最小 DOM:

js 复制代码
testHtml2canvas141()

成功后再验证当前业务 DOM:

js 复制代码
testHtml2canvasCurrentDom()

最终结果:

  • 最小 DOM 可以生成 canvas。

  • 当前业务 DOM 可以继续生成图片。

  • 1.4.1 的样式表现优于旧 plugin 版本。

经验总结

这次问题容易被误判成业务 DOM 或 CSS 问题,因为 html2canvas 的报错栈经过压缩后很难直接读,vConsole 里显示的 t.match 也不一定是根因。

更有效的排查路径是:

  1. 先确认实际加载的是哪一个 html2canvas 文件。

  2. 用极简 DOM 做最小复现。

  3. 如果极简 DOM 也失败,就优先排查 html2canvas 初始化、clone、iframe、资源加载这些基础流程。

  4. 观察 html2canvas 日志停在哪一步。

本次的关键判断点是:极简 DOM 也卡在 Starting document clone...,所以问题不在业务 DOM,而在 1.4.1 的隐藏 iframe clone 等待逻辑。

相关推荐
To_OC5 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel7 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_9 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx9 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师9 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow9 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路9 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他10 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou13210 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙10 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript