【问题标题】:AngularJS - Use ES6 imports instead of angular DI systemAngularJS - 使用 ES6 导入而不是 Angular DI 系统
【发布时间】:2018-02-10 16:05:08
【问题描述】:

我正在使用带有 Angular 1.6.x 和 Typescript 的 Webpack,我退出使用 Angular DI 以支持 ES6 导入。当我需要一些像 $http、$resource 这样的 ng 函数时,我会通过装饰器直接使用 angular.injector 函数注入它们,如下所示:

// 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]);

我不知道它是否符合最佳做法,但到​​目前为止它运行良好。

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

【问题讨论】:

  • Angular 模块/DI 和 ES6 模块相互补充。它们不可互换。 直接使用 angular.injector - 这是非常错误的,您将很少需要使用 angular.injector,因为它不会按照您的预期进行。
  • 我觉得这是一个很好的问题,但在这里写的不合适。你的代码是完全可用的,这是第一个危险信号,以及几乎直接在dont-ask 中引用的声明“我想听听你对这个主题的想法”。我确实认为这个问题有其优点,但您可能需要考虑重新措辞,以便更多地了解这种技术的方式和原因,以进行质量检查,而不是讨论。

标签: angularjs typescript ecmascript-6


【解决方案1】:

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

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

使用 ES6 或 TypeScript 的推荐方法是按照惯例进行 DI,使用 $inject 注释:

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

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

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

它的default export 是模块名,可以导入到另一个直接依赖它的模块中:

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

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

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

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

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

【讨论】:

  • 谢谢。我确实知道您在此处发布的这种方法,但只是想出了使用 angular.injector 通过装饰器使用 angular 私有函数的想法,并且不知道它是否是一个好方法。我想我现在会坚持使用角度 DI。
  • 去过那里,做到了。不,这肯定不是一个好习惯。从理论上讲,在引导期间暴露一个注入器并在装饰器中使用它是可能的,但这可能会破坏事情,因为一次可能有多个注入器。答案中显示的样式通常对于 TypeScript 是可取的(对于 ES6 可能会有所不同)。
猜你喜欢
  • 2016-09-05
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 2011-10-15
  • 1970-01-01
  • 2019-06-27
  • 1970-01-01
  • 2012-11-13
相关资源
最近更新 更多