未指定providedIn的Angular服务注册作用域、影响及摇树优化问题
Angular服务未指定
providedIn时的那些事儿 1. 没写providedIn,服务到底注册到哪?
咱们平时写@Injectable({ providedIn: "root" })的时候,Angular会自动把服务注册到根DI容器,全局单例可用。但如果你只写@Injectable()不带配置,Angular不会自动帮你把服务放进任何DI容器——你得手动在某个NgModule的providers数组里声明它,或者在组件的providers里注册,它才会属于对应模块/组件的作用域。
举个实际代码例子:
// 只标注@Injectable()的服务 @Injectable() export class UserService {} // 必须手动在模块里注册才能用 @NgModule({ providers: [UserService] // 这时服务属于AppModule的作用域 }) export class AppModule {}
要是你既没加providedIn,又忘了在providers里注册,那注入这个服务的时候直接就会报DI找不到的错误,踩过这个坑的应该都懂😂。
2. 不指定作用域会有啥坑?
- 依赖关系乱成麻:项目小的时候还好,一旦模块变多,很容易不小心在多个模块的
providers里都注册同一个服务,结果就是每个模块都创建一个服务实例,状态不统一的bug分分钟找上门。 - 灵活性大打折扣:如果服务是在某个模块里注册的,其他模块要用到的话,要么导入整个模块,要么再注册一遍,远不如
providedIn: 'root'那种全局单例来得省心。 - 内存开销隐形增加:要是你在组件的
providers里注册服务,那每次组件实例化都会新建一个服务对象,频繁创建销毁的话,多余的内存占用就找上门了——当然,如果你本来就需要每个组件一个实例,那另说。
3. 对Tree Shaking(摇树优化)的影响
这是最影响性能的点:
- 用
@Injectable({ providedIn: "root" })的时候,Angular会给服务打上树可摇标记。意思是如果你的代码里从来没注入过这个服务,Webpack这类打包工具就能把它从最终的bundle里彻底删掉,帮你减小包体积。 - 但如果是
@Injectable()+手动在模块providers里注册的方式,这个服务会被当成模块的强制依赖——哪怕你从来没在代码里用过它,打包工具也没法把它摇掉,因为模块的providers数组会强制把它包含在打包结果里。
总结一下:不指定providedIn的写法,直接就把Tree Shaking的路堵死了,无用代码删不掉,包体积自然就大了。
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

