libpag在web中的一些使用问题

2,099 阅读3分钟

一、问题出现

测试同学发现页面打开多个标签页后,有一些页面的pag动效会渲染错误,变成一个白色正方形的哭脸表情

二、问题排查

1. pag文件是否请求正常

在环境打开控制台,刷新页面,发现pag文件都是正常请求到了,动效也正常显示。那看来并不是文件的问题

2. 多个页面的问题吗?

在环境中,尝试连续打开2个标签页,页面正常显示。

尝试连续打开3个标签页,页面正常显示。

尝试连续打开4个标签页,第一个打开的页面中的4个动效出现了哭脸表情

!cool,问题复现了,不错不错,就怕复现不了的BUG。打开控制台,发现Console有提示,看来是什么东西被删掉了

image.png

复制这个错误 Too many active WebGL contexts. Oldest context will be lost.,去libpag的社区找找有没有相关的错误,果然找到相关的答案 1484,官方的回答如下:

image.png

问题定位到了,就是一个页面里面创建了太多PAGPlayer了(一个页面用了5个PAGPlayer,相当于用了5个active WebGL contexts),4个标签页需要用20个,超出了chrome的16个限制,那么之前的就会被丢掉,渲染错误,就会出现哭脸。

三、问题解决

1. 官方提议

在上面官方的回答中,提议使用组合 PAGComposition 的方式渲染,就是把多个pag文件放到一个canvas里面去渲染,那就只用了1个active WebGL contexts,问题基本就解决了。

但是我这个页面比较特殊,动效的位置很分散,且嵌套在不同的组件里面,用一个canvas去渲染很明显是不现实的,所以官方的解决方法不太适合

image.png

2. 尝试解决

有没有一种可能,在标签不显示的时候,这个动效其实并没有起作用,那我是不是可以直接销毁掉,等标签显示的时候再渲染就好了。好像有搞头,试一下

加上一个函数 watchVisibility 用于监听标签显隐,标签隐藏的时候,执行destroy方法

const watchVisibility  = () => {
    document.addEventListener('visibilitychange', () => {
        if (document.hidden) {
            // 销毁 PAGPlayer
            if (PAGPlayer) {
                PAGPlayer.destroy();
                PAGPlayer = null;
            }
        } else {
            // 创建 PAGPlayer
            if (!PAGPlayer) {
                nextTick(() => {
                    initPag();
                });
            }
        }
    });
};

试验一下,连续打开4个页面,结果第1个打开的页面还是会出现错误的提示。

3. 原来要这样?

看来destroy并没有能清除掉WebGL的上下文,只能继续在网上找找解决方法。这个问题如果是canvas的限制,那是不是其他的框架也有这个问题?

这次我直接搜 Too many active WebGL contexts. Oldest context will be lost.,找到了 这个

原来可以手动销毁上下文,好像有搞头,试一下

<canvas v-if="!docuemntHidden"></canvas>
const watchVisibility  = () => {
    document.addEventListener('visibilitychange', () => {
        if (document.hidden) {
            // 销毁 PAGPlayer
            if (PAGPlayer) {
            
                // 销毁canvas引用的GL上下文
                PAGPlayer.canvasElement.getContext('webgl')
                    .getExtension('WEBGL_lose_context')
                    .loseContext();
                    
                PAGPlayer.destroy();
                PAGPlayer = null;
            }
            
            docuemntHidden.value = true;
        } else {
            // 创建 PAGPlayer
            
            docuemntHidden.value = false;
            if (!PAGPlayer) {
                nextTick(() => {
                    initPag();
                });
            }
        }
    });
};

找到PAGPlayer引用的canvas,手动销毁WebGL的上下文,再给渲染的canvas标签加上渲染条件

试验一下,连续打开4个页面,再打开第一个标签,正常显示动效,似乎是解决了,尝试多几个标签切换,确实没问题。

FF和Edge也不放过,也没问题,看来这个解决方式可行,COOL!