记一前端缺陷

20201128.jpg

昨天遇到了一个前端问题,作为这个方面的新人,基本上无力解决。在美丽的前端小姐姐的指点下,直到今天才弄明白这个问题。

背景

某个 Web App,可以从本地上传一张图片(但只留在浏览器端),图片缓存在会话中。刷新或者跳跃回本页的时候,从会话缓存里取出缓存绘制出来。而在上传图像之前,绘图板保持空白。图像输入,不论是用户上传,还是从缓存里加载,都是自由模糊类的输入,为此注册了画板的 onerror 事件,显示出错误消息框。错误消息框上的提示信息,类似是「无法加载图片」,但本 App 有国际化要求,视某个选项的可能变成其他语言。所以信息的文本实际上是从 i18n 的配置中提取出来的。

问题

测试出现了 BUG。在不加载任何图片,刷新页面时,有一定的概率会弹出无法加载图片的错误消息框。而且错误消息并不是正确国际化的内容,而是到此配置项目的键路径,类似是:webapp.cannot_load_image

有经验的前端小姐姐很轻松的找出了弹出错误框的原因,在画框的 <img> 标签里,错写了 src="#" 属性。这会让浏览器加载到此时请求一张跟当前 URL 路径一致的资源,并当作图片解析。也就是得到了本页的 HTML,却要认为它是图片,这是产生错误的根本原因。

这只是一个不大不小的错误,在编码过程中出现这种情况是很正常的现象。只要将 src 属性整个删去即可。但这个现象距离完全解释清楚还有很长的路要走。

  • 为什么这个错误不是稳定产生的,而是随机产生的?
  • 为什么国际化出了错误?

实际上,每次因为 src 的错误加载了错误的图像,HTML 一定会被请求过来,但是这个请求会不会产生错误,要看这时的 onerror 事件有没有注册。惯例来说,页面的 Js 会控制在 DOM 加载完成之后在注册这类事件,而这个时机和错误的图片返回回来的时机谁先谁后完全不可知。

所以说,在初始加载的过程中,我们不能期望 onerror 发挥作用。

国际化错误的原因肯定跟国际化方案联系在一起,此页加载了国际化工具 Js:some_i18n_prepare.js,但此准备工作的进行却是异步的。类似:

window.i18n.prepare(foo, bar).call(() => {
   $(document).trigger('i18n-ok');
   // something else
});

所以,在 src 加载触发了错误,并触发了 onerror 时(一定在 DOM 加载完之后),i18n 库的准备还没有完成,此时提出的错误消息,是一个没替换的键就不足为奇了。实际上,这个 some_i18n_prepare.js 已经为此准备了接口,在加载完成之后会触发 i18n-ok 事件。

上传图片此事不需要过度担心;空图片的情况,去掉 src 即可解决;而从缓存加载图片时,为了保证 onerror 在错误时有效,也应该将加载过程放在 i18n-ok 事件的回调里。

此外,这还解决了另一个此 App 上,以此同样的原因产生的问题,这也就是题外话了。

番外

在定位问题的过程中,小姐姐还教导我,Js 中注册的任务有微任务和宏任务之分,并且利用 setTimeout 强行让注册错误发生在 i18n 准备之后。也是一番神仙操作。

参见

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 13,855评论 1 32
  • jHipster - 微服务搭建 CC_简书[https://www.jianshu.com/u/be0d56c4...
    quanjj阅读 4,251评论 0 2
  • 性能优化方向分类 请求数量: 合并脚本和样式表, CSS Sprites, 拆分初始化负载, 划分主域(使用“查找...
    Www刘阅读 5,768评论 3 8
  • Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践。他们为此进行了一系列...
    拉风的老衲阅读 5,839评论 0 1
  • 2019.6.13 星期四 雨 早上起来就觉得冷,给小宝穿了套薄的长袖长裤,抱出去不断有人说...
    萋萋白露阅读 741评论 0 1