Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

icejs 中 store 加载时机过前问题 #3630

Closed
luhc228 opened this issue Oct 10, 2020 · 5 comments
Closed

icejs 中 store 加载时机过前问题 #3630

luhc228 opened this issue Oct 10, 2020 · 5 comments
Assignees
Labels
Milestone

Comments

@luhc228
Copy link
Collaborator

luhc228 commented Oct 10, 2020

store 加载时机过前,导致在 model 中最初拿到的 APP_MODE 的值是 undefined。应该是在 config > createApp > other(model/router/...)

@chenbin92 chenbin92 added the bug label Oct 13, 2020
@chenbin92 chenbin92 added this to the 1.9.8 milestone Oct 14, 2020
@luhc228
Copy link
Collaborator Author

luhc228 commented Oct 16, 2020

问题

basic-store 为demo,进行代码部分修改,以呈现问题:

src/models/counter.ts 加入以下代码:

+ import { IRootDispatch, APP_MODE } from 'ice';

+ console.log('store: APP_MODE === ', APP_MODE);

src/app.ts 中加入以下代码:

+ import { APP_MODE } from 'ice';
+ console.log('app APP_MODE ===' APP_MODE);

我们在项目的根目录下执行 npm start,看下控制台上打印的结果:

image

可以看到有两个问题:

  • app.ts 中打印的内容,会在 counter.ts 的打印内容之后。正常来说,我们更期待的是,二者打印顺序是相反的
  • counter.ts 中,打印的 APP_MODEundefined

.ice/index.ts 中,我们会发现有一段代码:

export const APP_MODE = (global as any).__app_mode__ || process.env.APP_MODE;

不妨试下在 counter.ts 中打印以下的内容:

+ console.log(process.env.APP_MODE);

你会发现,这里打印出来的值为 start

分析

问题一

我们都知道,ES Module 是静态编译的。import 的命令会在代码运行前,被 JS 引擎静态编译分析,具有提升作用,会优先于模块中其他内容执行的。比如下面的一个例子:

// a.js
console.log('a.js')
import { foo } from './b';

// b.js
export let foo = 1;
console.log('b.js');

// 执行结果:
// b.js
// a.js

框架的入口为应用的 src/app.ts。在执行 src/app.ts 中,引擎发现它加载了 .ice/index.ts,因此会优先执行 .ice/index.ts

// src/app.ts
import { createApp, IAppConfig, APP_MODE } from 'ice';

console.log('app APP_MODE ===' APP_MODE);

const appConfig = {};

createApp(appConfig);

.ice/index.ts 中,又看到加载了 ./store/index.ts ,现在去执行 ./store/index.ts

// 此处省略代码
import store from './store/index';

export { store };

./store/index.ts中,会引用 src/models/counter.ts,然后去执行 src/models/counter.ts。等待执行完 src/models/counter.ts后,再回去执行 src/app.ts。因此,第一个问题就有答案了。

问题二

在解第二个问题时,先看下一般情况使用 ES Module:

// a.js
console.log('a');
import { foo } from './b.js';
console.log(foo);

// b.js
const foo = 2;
console.log('b');
export { foo };

// 输出内容
// b
// a
// 2

在执行 a.js ,JS 引擎静态编译时,遇到 import 的时候,会先执行 b.js ,执行完以后再执行 a.js 。这也就是为什么先打印 b,后打印 a。

下面我们再看一下 ES Module 循环依赖的情况:

// a.js
import { bar } from './b';
console.log('a.js');
console.log(bar);
export const foo = 'foo';

// b.js
import { foo } from './a';
console.log('b.js');
console.log(foo);
export const bar = 'bar';

// 执行 a.js 后,输出结果为:
// b.js
// undefined
// a.js
// bar

由于在执行 b.js 时候,由于之前已经加载过 a.js,因此不会再执行重复加载的模块,但是,a.js还没有执行完 foo = 'foo'。因此会打印出输出 undefined

解决办法是导出 getFoo 函数,因为函数有提升作用:

// a.js
import { bar } from './b';
console.log('a.js');
console.log(bar);

export const function getFoo() { return 'foo' };

// b.js
import { foo, getFoo } from './a';
console.log('b.js');
console.log(getFoo());
export const bar = 'bar';

// 执行 a.js 后,输出结果为:
// b.js
// foo
// a.js
// bar

回到问题二,我们现在的模块依赖关系是:

src/app.ts --> .ice/index.ts --> .ice/store/index.ts --> src/models/counter.ts --> ./ice/index.ts

这里面形成了模块循环依赖,因此,APP_MODEsrc/models/counter.ts中调用时,还没有被赋值。因此打印出来的是 undefined

总结

如果不使用自定义创建 store 的方式,由框架自动创建 store,是会有模块循环依赖的问题。如果使用自定义创建 store 实例方式使用状态管理,则没有上面的问题。模块依赖关系如下:
image

@chenbin92
Copy link
Collaborator

在执行 a.js ,JS 引擎静态编译时,遇到 import 的时候,会先执行 b.js ,执行完以后再执行 a.js 。这也就是为什么先打印 b,后打印 a。

遇到 import 的时候,会先执行 b.js 应该是 import 会进行提升,类似 var 变量作用域提升效果

@chenbin92
Copy link
Collaborator

chenbin92 commented Oct 26, 2020

目测已有的实现是存在问题的。可以通过以下三种方式获取到正确的 APP_MODE

  1. process.env.APP_MODE
  2. getAppMode()
  3. 调整 appMode 的调用顺序 @imsobear

结论:3

@luhc228
Copy link
Collaborator Author

luhc228 commented Oct 29, 2020

发布 [email protected] 已修复

@luhc228 luhc228 closed this as completed Oct 29, 2020
@luhc228 luhc228 reopened this Dec 1, 2020
@luhc228 luhc228 mentioned this issue Dec 7, 2020
7 tasks
@imsobear imsobear assigned ClarkXia and unassigned luhc228 Dec 9, 2020
@luhc228 luhc228 closed this as completed Dec 14, 2020
@luhc228
Copy link
Collaborator Author

luhc228 commented Dec 14, 2020

发布 [email protected] 版本已解决

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants