Angular service的单例模式

喵先生的进阶之路

问题描述

前台在的菜单,需要向后台进行请求,但是这样就造成每次点击一个菜单都会重新请求,造成菜单会出现短暂闪烁的情况,所以考虑使用service的单例模式来解决这个问题。

service 单例模式

angularjs中,service默认都是单例的,但是在angular中,取消了这种默认。虽然我们说单例模式是好的,但是很多时候我们真的需要service是单例的吗?

比如我们经常使用的表格,大部分情况下,我们只是需要将信息展示出来,并不需要使用service对其进行缓存,因为它不会被别的模块所使用。

那么,在angular中如何使service为单例的呢?

实现

其实,在angular6之前,如何我们想声明一个service供全局使用,是这样设置的:

服务:

export class TestService { }

根模块:

@NgModule({
  declarations: [...],
  providers: [TestService],
  bootstrap: [AppComponent]
})
export class AppModule {}

我们需要在@NgModule中去声明providers,将service共全局使用,成为单例。

但是从angular6开始,单例模式又变成了一个首选方式。

所以,只要我们使用angular-cli的命令创建service的时候,就会默认创建如下部分:

@Injectable({
    providedIn: 'root',
})

这时,就声明该service在整个项目的模块下是单例的了。

当然,此时使用原来在@NgModuleproviders的方式也是可以的。

我的应用

我的目的是避免重复请求后台,所以基本思路就是在一次请求后台之后,将请求结果交给service保管,然后,然后下次请求就直接获取service中的数据就可以了。

@Injectable({
    providedIn: 'root',
})
export class MenuService {
    private baseUrl = 'menu';
    private currentMenuList: Array<Menu>;      // 这里存储所有的菜单

    constructor(private http: HttpClient) {
    }

    /**
     * 请求后台,获取所有菜单
     */
    getAll() {
        return this.http.get<Menu[]>(this.baseUrl);
    }

    /**
     * 设置当前菜单列表
     * @param menuList 菜单列表
     */
    setMenuList(menuList: Array<Menu>) {
        this.currentMenuList = menuList;
    }

    /**
     * 获取当前菜单列表
     */
    getMenuList() {
        return this.currentMenuList;
    }
}
export class LeftControlComponent implements OnInit {
    menuList: Menu[];      // 菜单

    constructor(private userService: UserService,
                private menuService: MenuService) {
    }

    ngOnInit() {
        this.initMenu();
    }

    /**
     * 初始化菜单
     */
    initMenu() {
        // 当前菜单为空的时候,重新请求菜单
        if (!this.menuService.getMenuList() || this.menuService.getMenuList().length === 0) {
            this.userService.getCurrentLoginUser()
                .subscribe((data: User) => {
                    this.menuList = data.role.menuList;

                    // 将获取的菜单交由service保存
                    this.menuService.setMenuList(this.menuList);
                }, () => console.log('network error!'));
        } else {
            // 直接使用保存的菜单
            this.menuList = this.menuService.getMenuList();
        }
    }
}

这样,只用在登录进行系统的时候获取一次菜单,后面都不用进行向后台的请求了。闪烁的问题也就消失了。


相关参考:
https://segmentfault.com/a/11...
https://angular.cn/guide/sing...

阅读 1.8k

朴世超
个人学习总结与项目实战问题记录
336 声望
19 粉丝
0 条评论
你知道吗?

336 声望
19 粉丝
宣传栏