关于低端机型上 H5 页面白屏的排查过程

September 23, 2022

问题

九月的某一天,QA 同学反馈在 OPPO R9 中打开我们的 H5 页面时遭遇白屏。

本篇文章记录我是如何按照从【复现 → 排查 → 修复 → 召回 → 总结】这一方法论解决工作中遇到的实际线上问题。

复现

考虑到 OPPO R9 发售于 2016,我猜测大概率是因为 JavaScript 引擎暂不支持 ES6 及以上的语法,导致执行出错。

为了验证该想法,我使用公司的 “机架”(一个可以远程运行真机的平台)进行复现。

远程调试后,Console 显示报错:"SyntaxError: Unexpected reserved word".

排查

报错信息的意思是:“代码使用了保留字作为变量”。

举个例子,let name = 'jack' 这里的 let 是一个系统保留字,但当用户环境不支持 let 时,它就会被视为单纯的变量,与保留字冲突,从而引发了 JS 语法错误,核心是用户环境不支持 ES6 语法。

使用 Chrome Sources Panel 进行搜索后,确实在产物代码中找到 ES6 语法 —— let,而这代码来自于一个内部的 JS SDK.

为了验证确实为 ES6 兼容性问题,发现使用同年秋季发售的 OPPO R9s 能正常打开 H5.

以下为两款机型的参数比对:

OPPO R9 发售于 2016.3 OPPO R9s 发售于 2016.10
Android 5 Android 6
Android System WebView/ Chrome 43 Android System WebView/ Chrome 55

根据 Chrome 对 ES6 的支持程度 https://caniuse.com/?search=es6 显示:

  • Android System WebView/ Chrome 43 部分支持 ES6
    • let Only supported in strict mode
  • Android System WebView/ Chrome 55 完全支持 ES6

假设没有“机架”的存在,该如何是好?

借助 es-check,我们能检测产物文件 ES 版本是否满足我们所指定的 ES 版本

ES Check checks JavaScript files against a specified version of ECMAScript (ES) with a shell command. If a specified file's ES version doesn't match the ES version argument passed in the ES Check command, ES Check will throw an error and log the files that didn't match the check.

举个例子:

js
// dist.js
"use strict";
let my_age = 24;
console.log(my_age);
js
// dist.js
"use strict";
let my_age = 24;
console.log(my_age);

运行 es-check es5 dist.js,会显示报错:

shell
error: ES-Check: there were 1 ES version matching errors.
info:
ES-Check Error:
----
· erroring file: dist.js
· error: SyntaxError: The keyword 'let' is reserved (3:0)
· see the printed err.stack below for context
----
SyntaxError: The keyword 'let' is reserved (3:0)
shell
error: ES-Check: there were 1 ES version matching errors.
info:
ES-Check Error:
----
· erroring file: dist.js
· error: SyntaxError: The keyword 'let' is reserved (3:0)
· see the printed err.stack below for context
----
SyntaxError: The keyword 'let' is reserved (3:0)

如果运行 es-check es6 dist.js,则会显示检测通过:

shell
info: ES-Check: there were no ES version matching errors! 🎉
shell
info: ES-Check: there were no ES version matching errors! 🎉

修复

了解原因后,修复手段也非常简单,有以下两种方式:

  1. 将 JS SDK 的 TypeScript 编译选项 target 设置为 ES2015
  2. 将 JS SDK 显式设置为 Babel 的处理对象之一

召回

诚然,在我们内部的监控平台上,由 "Unexpected reserved word" 衍生的同类 JS 错误还有许多,归根到底是低版本浏览器不兼容 ES6 +:

js
Uncaught SyntaxError: Unexpected token =>
js
Uncaught SyntaxError: Unexpected token =>
js
Uncaught SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
js
Uncaught SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

令人遗憾的是,虽然上述错误被成功召回,但由于在监控大盘中量级过小被忽视了。

总结

  • 用好“机架”、es-check 等工具辅助排查
  • 做好低端机型的兼容性工作,如 ES Version,Browser API
  • 重视监控平台的上报告警,不放过任何一个错误

B2D1 (包邦东)

Written by B2D1 (包邦东)