记一次报错

记一次报错
Photo by Wolfgang Hasselmann / Unsplash

今天遇到一个错误,启动应用时,直接崩溃,报错

Stacktrace:
SourceMap is not initialized yet 
    at PreferenceModel (entry|entry|1.0.0|src/main/ets/utils/PreferenceModel.ts:30:56)
    at func_main_0 (entry|entry|1.0.0|src/main/ets/utils/PreferenceModel.ts:187:16)
    
//PreferenceModel.ets 文件结构
class PreferenceModel {
}
const SpUtil = new PreferenceModel();
export default SpUtil;

PreferenceModel是用于记录应用配置项的一个类,这里是由于在PreferenceModel的构造函数中获取保存的context失败,导致异常。
但是问题在于:

  1. context是直接在应用的入口EntryAbility.onCreate()进行保存的不应该失败
  2. 在应用的启动入口处没有调用PreferenceModel的方法
  3. 在出问题前后PreferenceModel没有任何修改
    后面发现PreferenceModel的初始化早于EntryAbility.onCreate。

这就很奇怪。

后面通过版本控制,一个文件一个文件的回滚,找到问题

//在Util.ets文件中
import { loginFromSplash } from '../pages/account/LoginPage';

export class Utils {

  static finishPageAndLogin(ctx: UIContext) {
    // ctx.getRouter().clear();
    // Utils.replaceUrl(ctx, { url: "pages/account/LoginPage", params: { param: LoginFrom.SPLASH } });
    loginFromSplash(ctx);
  }

}

//在LoginPage.ets文件中
export function loginFromSplash(ctx: UIContext) {
  ctx.getRouter().clear();
  Utils.replaceUrl(ctx, { url: "pages/account/LoginPage", params: { param: LoginFrom.SPLASH } });
}

struct LoginPage {}

问题出在finishPageAndLogin()方法,注释的是没问题的代码,loginFromSplash()是出问题的代码。
loginFromSplash()这个方法在应用入口处也完全没有调用,为什么会有问题。

原因:因为在应用入口处有使用Utils,会导致Utils文件中的所有import立即执行,又由于finishPageAndLogin()函数调用loginFromSplash(),导致LoginPage加载,LoginPage中又使用LoginViewModel类,LoginViewModel中有import SpUtil from '../utils/PreferenceModel';
那么也就是虽然在应用入口处,没有调用上述任何一个方法,但是由于import链

Utils.ets
  └── import LoginPage.ets
        └── import LoginViewModel.ets
              └── import SpUtil (PreferenceModel.ets)
                    └── new PreferenceModel()
                          └── 获取 context 失败!💥

导致了这个问题发生。

那么如何防御这种问题,根据ai回答:工具类不用import 页面,避免将整个页面依赖树拖进来。