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 等待逻辑。

相关推荐
JustHappy2 小时前
古法编程秘籍(七):互联网到底是什么?把两台电脑怎么说话搞懂就够了
前端·后端·网络协议
snow@li2 小时前
SEO-文章标题:写文章时候,分类+主标题+大纲+解释 作为标题 / 不点进去也知道全文覆盖什么 / 标题即架构
前端
kyriewen3 小时前
Git Commit 前自动修复代码风格?配置 Husky + lint-staged,从此 CR 只聊逻辑
前端·git·面试
小和尚同志3 小时前
AI 自动化测试探索(一):Playwright MCP
前端·人工智能·aigc
老马识途2.04 小时前
在AI的帮助下理解spring的启动过程
java·前端·spring
徐小夕4 小时前
Loop Engineering 深度解析与实战指南(全网最全)
前端·算法·github
运筹vivo@4 小时前
Python ContextVar 底层机制与内存模型拆解
前端·数据库·python
#麻辣小龙虾#6 小时前
基于vue3.0开发一款【固废与废气运维管理系统】(支持源码)
前端·vue.js·vue3
Cosolar6 小时前
Docsify零构建文档站完全指南:从快速搭建到企业级部署
前端·开源·github
weixin_471383036 小时前
Taro-02-页面路由
前端·taro