ecomfe/esl

一个复杂的包含resource场景的依赖,加载过程无法完成

errorrik opened this issue · 1 comments

foo -> bar -> tpl!x
empty

如果tpl!x已经预先require并ready时

  • require(['foo'],callback) 时,callback被调用,但是未来foo模块将不存在
  • require(['foo', 'empty'],callback) 时,callback不被调用

原因是因为,modAutoDefine会对每个需要自动定义的模块进行modPrepare、modUpdatePreparedState、modTryInvoke调用。modUpdatePreparedState中,会尝试调用其依赖模块的modPrepare。如果模块包含resource依赖,modPrepare中会在尝试在resource加载完后重新调起modAutoDefine。当resource当前已经处于ready状态时,这个过程会马上发起。从而导致一个运行过程中,同一个模块的modUpdatePreparedState被重入。而modUpdatePreparedState中,对模块状态的写入没有做判断,从而导致模块状态可能从defined回退到prepared。

过程如下:

script onload -> modAutoDefine -> modPrepare(foo) -> modUpdatePreparedState(foo) -> modPrepare(bar) -> requireResource -> modAutoDefine -> modPrepare(foo)  -> modUpdatePreparedState(foo) -> modTryInvoke(foo) -> modTryInvoke(foo)

由于:

  1. resource加载完后重新调起modAutoDefine是合理的。因为resource加载可能是异步过程。所以这里不能干掉
  2. modUpdatePreparedState不可重入控制的话,增加代码量会多一些

所以,采用解决方案为:modUpdatePreparedState中,对模块状态的写入做判断

if (!modIs(id, MODULE_PREPARED) {
    mod.state = MODULE_PREPARED;
}