AngularJS - 使用 ES6 导入而不是 Angular DI 系统 [英] AngularJS - Use ES6 imports instead of angular DI system

查看:13
本文介绍了AngularJS - 使用 ES6 导入而不是 Angular DI 系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有 angular 1.6.x 和 Typescript 的 Webpack,并且我不再使用 angular DI,转而使用 ES6 导入.当我需要一些诸如 $http$resource 之类的 ng 函数时,我通过装饰器直接使用 angular.injector 函数注入它们,例如这个:

I'm using Webpack with angular 1.6.x and Typescript and I quit using angular DI in favor of ES6 imports. When I need some ng functions like $http, $resource and such I inject them directly using the angular.injector function through a decorator, like this:

// inject.ts
    import * as angular from 'angular';

    export function inject (...params: string[]) {

        function doCall ( param: string, klass: Function) {
            const injector = angular.injector([ 'ng' ]);
            const service = injector.get(param);
            try {
                klass.prototype[ param ] = service;
            } catch ( e ) {
                window.console.warn( e );
            }
        }

        // tslint:disable-next-line:ban-types
        return function ( klass: Function ) {
            params.forEach( ( param ) => {
                doCall( param, klass );
            } );
        };
    }

// posts.service.ts
import { inject } from './inject';
import { IPost, Post } from './post';

@inject('$http')
export class PostsService {
    public $http: angular.IHttpService;
    get (): Promise<IPost[]> {
        const posts: IPost[] = [];
        const promise = new Promise<IPost[]>( (resolve, reject) => {
            this.$http.get<IPost[]>('https://jsonplaceholder.typicode.com/posts')
            .then(( response ) => {
                response.data.forEach(item => {
                    posts.push( new Post(item) );
                });

                resolve( posts );
            });
        });

        return promise;
    }
}


// post.ts
export interface IPost {
    userId: number;
    id: number;
    title: string;
    body: string;
}
export class Post implements IPost {
    userId: number;
    id: number;
    title: string;
    body: string;

    constructor (item: IPost) {
        this.userId = item.userId;
        this.id = item.id;
        this.title = item.title;
        this.body = item.body;
    }
}


// controller.ts
import { IPost } from './post';
import { PostsService } from './posts.service';

export class Controller {
    public postService: PostsService;
    public posts: IPost[];
    constructor ( private $scope: angular.IScope ) {
        this.postService = new PostsService();
    }

    $onInit () {
        this.postService.get()
        .then((posts) => {
            this.posts = posts;
            this.$scope.$digest();
        });
    }
}

// index.ts
import * as angular from 'angular';

import { Controller } from './app/controller';

import './index.scss';

export const app: string = 'app';

angular
  .module(app, [])
  .controller('controller', Controller);


angular.bootstrap(document.body, [app]);

我不知道它是否符合最佳实践,但到目前为止它运行良好.

I don't know if it's in compliance with best practices or not, but it is working quite nicely so far.

我想听听您对这个主题的看法:使用这种方法是否有任何问题(性能、不良做法等)?

I would like to hear your thoughts on the subject: is there any problem (performance, bad practice and such) using this approach?

推荐答案

ES 模块不能替代 Angular 模块和 DI.它们相互补充并保持应用程序的模块化和可测试性.

ES modules cannot replace Angular modules and DI. They compliment each other and keep the application modular and testable.

ES6 模块提供了额外的可扩展性层,例如控制器/服务子类化(单独使用 Angular 模块和 DI 看起来不太好).

ES6 modules provide extra layer of extensibility, for example controller/service subclassing (something that doesn't look good with Angular modules and DI alone).

推荐使用 ES6 或 TypeScript 的方法是使用 $inject 注释进行传统的 DI:

The recommended approach with ES6 or TypeScript is to do DI conventionally, with $inject annotation:

export class PostsService {
  static $inject = ['$http'];
  constructor(
    public $http: angular.IHttpService
  ) {}
  ...
}

每个文件有一个模块也是一种很好的做法,这样应用程序就可以保持模块化和可测试性:

It's also a good practice to have one module per file, this way the application stays modular and testable:

export default angular.module('app.posts', [])
  .service('posts', `PostsService)
  .name;`

它的默认导出是模块名称,可以导入到另一个直接依赖它的模块中:

Its default export is module name that can be imported in another module that directly depends on it:

import postsModule from '...';
...
export default angular.module('app.controller', [postsModule])
  .controller('controller', Controller)
  .name;`

通常无法从装饰器访问应用程序注入器.即使可以通过 hack 使其在生产中工作,它也会在测试中搞砸.

Application injector cannot be normally reached from a decorator. Even if it's possible with a hack to make it work in production, it will be messed up in tests.

angular.injector 创建新的注入器(即应用程序实例)并且在生产中的正确使用非常有限:

angular.injector creates new injector (i.e. application instance) and has very limited proper uses in production:

angular.injector(['ng']).get('$rootScope') !== angular.injector(['ng']).get('$rootScope');

当开发人员不知道如何获取当前的 $injector 实例时,它经常被误用.在这种情况下当然不应该使用它.

It is often misused when a developer doesn't know how to get current $injector instance. It certainly shouldn't be used in a case like this one.

这篇关于AngularJS - 使用 ES6 导入而不是 Angular DI 系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆