如何在WebWorker中使用psd.js

在正式看代码之前,请允许我先啰嗦一整儿。

还记得几年前,当时刚接手了前同事做的psd解析项目,设计师老是抱怨解析不稳定卡顿,准备做一些优化,当时的考虑是将psd.js放入WebWorker中去运行,卡顿情况可能会好一些,代码都写好了,最后发现在WebWorker中会报错,没法玩,由于网上没搜到任何关于这块儿的资料再加上当时时间比较紧张也没有继续深入研究下去,做了一些其他的优化后这个事情就搁置了。

最近又做了一个关于psd.js解析的需求,在项目中直接集成psd解析,场景是用户通过我们的在线app选择预先设计好的一组主题(以文件夹为单位),每组主题包含了一定数量的psd文件,我们需要将psd文件转换成系统能识别的数据并保存成主题,用户下次可以直接选用保存的主题并应用到书类项目中。
由于要解析的对象是一堆的psd文件,再加上psd解析非常的卡,所以我做了并发控制,同一时间只允许一个psd解析,一个解析完成再继续解析剩下的psd文件,虽然做了并发控制,但是单个psd的解析依然非常卡顿,严重影响页面的用户交互,比如关闭弹框等等,虽然知道WebWorker可能是解决卡顿问题的关键,但是因为时间问题没有时间去仔细研究,只能选用其他的优化方式,我将单个psd的解析步骤分解成多个并使用requestIdleCallback来回调,这样做虽然卡顿有所改善,但是当解析执行到关键节点时卡顿依旧,但还是就这么上了线。

作为一个技术人,每每想到遗留的这个问题就很难受,下定决心一定要找到psd.js在WebWorker中正常使用的方式。

我们先不考虑其他任何问题,直接将psd.js在WebWorker中使用,代码如下:

importScripts('js/psd.min.js');
const psd = require('psd');

self.onmessage = e => {
    const { file } = e.data;
    const url = URL.createObjectURL(file);
    psd.fromURL(url).then(parser => {
        console.log(parser);
    }).catch(err => {
        console.log(err);
    });
};

不出意外报了错,错误信息如下:

Uncaught TypeError: Cannot read properties of undefined (reading 'prototype') at y (psd.min.js:10:19147)

查看调用栈可以发现报错是因为const psd = require('psd');这段代码引起的,而这个是引入psd模块的代码,如果这个都报错,后续的解析更是想都不用想,接着我们尝试对报错的位置添加断点,通过回溯调用栈,我们可以发现如下代码:

...
).call(this, "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {})
...

解读一下这段代码,大致意思是:

1、如果存在global对象,则使用global对象,这是判断node环境。

2、如果存在self对象,则使用self对象,这是判断WebWorker环境。

3、如果1、2都不满足则使用window对象,缺省环境为浏览器环境。

按照上面的分析,psd.js其实对WebWorker环境有做判断,按道理应该是支持WebWorker环境的,但是为什么在WebWorker下会报错呢?通过不断调试,我们可以发现以下代码:

, Q = K[typeof window] && window || this
, J = K[typeof r] && r && !r.nodeType && r
, X = K[typeof t] && t && !t.nodeType && t
, ee = X && X.exports === J && J
, te = K[typeof e] && e;
!te || te.global !== te && te.window !== te || (Q = te);

其中变量Q就是关键,其初值为window或者thise为当前的环境对象globalselfwindowte.globalglobal.global,其值就是globalte.windowwindow.window, 其值就是window,我们分析一下最后的判断代码即每个状态下Q的值:

!te || te.global !== te && te.window !== te || (Q = te);

1、当te不存在或为null,此时Q = window

2、当te不等于globalte不等于window,即当前在WebWorker环境下,此时Q = this,因为WebWorker环境下没有window,所以Q = K[typeof window] && window || this取出来的初值应该是this

3、当条件1、2都不满足时,将te赋值给Q

按道理,这里需要判断的是当前是什么环境,并将所属环境的全局对象赋值给Q,但是上面的判断对于WebWorker的全局对象self来说却永远不可能得到正确赋值,我们需要让self对象在WebWorker环境下能正常赋值给Q,稍微修改一下上面的判断:

将代码:

!te || te.global !== te && te.window !== te || (Q = te);

修改为:

!te || te.global !== te && te.self !== te || (Q = te);

然后我们重新测试一下psd.js在WebWorker中的运行情况,发现报错已经没了,psd解析功能也完全没有问题,而且也并不会影响浏览器环境和node环境,搞定!!!。

测试demo:https://demo.deanhan.cn/psd-in-webworker/

如需下载本文涉及的源码及素材包,请在关注本站公众号后发送:psd

  • 支付宝二维码 支付宝
  • 微信二维码 微信

本文地址: /psd-in-webworker.html

版权声明: 本文为原创文章,版权归 逐梦个人博客 所有,欢迎分享本文,转载请保留出处!

相关文章