介绍一个帮助迁移到Angular 2的库angular-http-harness

大家好,我是拉科。我想你们这些喜欢尝新的人应该已经开始迁移到Angular 2了,但是关于$http的迁移怎么进行呢?
为帮助从Angular 1的$http迁移到Angular 2的Http,我开发了一个名为angular-http-harness的库。接下来,我将介绍它能解决哪些问题以及让你们从中受益的地方。

语言规范的统一

    • サービス: ビューから切り離されたアプリケーションまたはライブラリのロジック。

$http: Angular 1のHTTP通信モジュール

Http: Angular 2のHTTP通信モジュール

随着HTTP的转移带来的问题

我认为几乎所有的Angular 1应用程序都使用$http,所以我认为不需要再解释了,但是再说一遍,$http是Angular 1中非常方便的服务,用于进行(通常是Ajax)HTTP通信。

http的特点是它是基于Promise的API。例如,可以这样写一个简单的GET请求。

$http.get("/sample.json")
  .then(resp => {
    console.log(resp);
  })
  .catch(error => {
    console.error(error);
  });

并且,$http在大多数情况下被用于封装某种程度的服务,以进行抽象化和单元测试。例如,如果将执行上述请求的服务定义为SampleService,那么将如下所示。

class SampleService {

  constructor($http) {
    this.$http = $http;
  }

  getJSON() {
    return this.$http.get("/sample.json");
  }
}

通过将此SampleService传递给Angular 1的angular.service(),可以解决依赖于$http的问题,从而在使用时可正常工作。

angular.module("app.service").service("sampleService", ["$http", SampleService]);


class SampleController {

  constructor(sampleService) {
    this.sampleService = sampleService;
  }
}

让我们开始转移到Angular 2吧

当我们迁移到Angular 2时,我们通常会关注从指令和控制器到组件的转变,但服务层实际上更加重要。只要适当地进行模块化,组件基本上只负责将数据投影到视图中,如果数据不正确,则没有意义,而创建这些数据的是服务。因此,如果服务无法迁移,就无法继续进行组件化。

常见的迁移策略是创建临时副本的方法。通过复制现有的TestService来创建Ng2TestService,并将其与Http相关联。然后将依赖于TestService的指令和控制器也复制到Ng2TestService,并重新编写以依赖于它。

Angular 1的代码可以与Angular 2的具有相同功能的代码并存,这样就可以逐步迁移应用程序而不会破坏它。当一定数量的代码被复制后,可以重写根部分并丢弃Angular 1的代码。

然而,这种方法存在问题。由于需要暂时复制并修改Angular 1代码,所以会产生与现有Angular 1应用程序的功能开发差异。每当新增新功能或对现有代码进行修改时,都需要逐一在Angular 2中进行反映,这是非常繁琐的。为了避免这种情况,只能完全停止功能开发,并且所有工作时间都要用于迁移,这是一个问题。如果是一个良好的项目或团队,那就另当别论了,但通常情况下,即使工程师想要将其转为Angular 2,也不允许停止当前应用的开发。

特别是$http会进行HTTP通信,所以需要与服务器端协同合作,而不仅仅是客户端。如果服务器端的API发生更改,服务也必须相应地进行调整。

换句话说,在推进Angular 2的同时,也需要跟进对现有应用程序的更改。

角度-HTTP-马具

为了达到这个目的,我创建了 angular-http-harness。这个库可以将HTTP通信服务分成“DI入口点”和“服务逻辑”,以便在Angular 1和Angular 2中可以使用相同的服务。换句话说,由于使用了共同的逻辑,所以Angular 1的更改会自动反映出来。

HttpHarness类

angular-http-harness提供的功能只有HttpHarness类。这是一个包装器,它通过抽象化,将Angular 1的$http和Angular 2的Http的差异吸收并以相同的接口进行处理。

首先,将现有的Angular 1服务重写为使用HttpHarness。然后,将这个类保留为一个抽象类,而不是直接使用它。一眼看上去,它与在Angular 2中使用Http的服务代码几乎没有什么区别!

请注意,此后的代码是以Angular 2为基础的TypeScript。

export abstract class TestService {
   private http: HttpHarness;

   constructor(http: HttpHarness) {
       this.http = http;
   }

   get(id: string): Observable<TestModel> {
       return this.http.get(`/${id}`)
           .map(resp => resp.json() as TestModel);
   }
}

HttpHarness在基本上具有与Http相同的接口。get和post方法的返回值是Observable。

创建一个用于Angular 1的服务。

接下来,我们将创建一个新的Angular 1服务。创建Ng1TestService类,并继承之前创建的TestService。在Ng1TestService类中,我们只需要处理Angular 1特有的部分,也就是DI的解决方案。在构造函数中接收$http,并用HttpHarness.fromNg1($http)进行封装,然后将其传递给父类TestService。

重要的是,在.service()函数中提供的不是TestService,而是Ng1TestService。服务的名称(”testService”)没有改变,因此使用服务的一方(控制器或指令)只需要简单地将Promise转换为Observable就可以了。RxJS还提供了一个名为Observable#toPromise()的方法,因此几乎不需要改动现有的代码,只需添加一个方法即可(尽管在将来应该替换为Observable的subscribe)。

export class Ng1TestService extends TestService {

    constructor($http: angular.IHttpService) {
        super(HttpHarness.fromNg1($http));
    }
}

angular.module("app").service("testService", ["$http", Ng1TestService]);

让我们首先确认当前应用程序没有受到任何影响。

创建一个Angular 2服务

创建Angular 2服务非常简单。只需创建一个Ng2TestService类继承TestService类,并在构造函数中将HttpHarness.fromNg2(http)传递给父类即可。由于所有逻辑都由TestService持有,因此不需要复制并修改为Angular 2特定的逻辑。

@Injectable()
export class Ng2TestService extends TestService {

    constructor(http: Http) {
        super(HttpHarness.fromNg2(http));
    }
}

好处

利用angular-http-harness来通用化服务逻辑,并且只分割DI的入口点,这样就可以无需影响现有应用程序,也无需停止功能开发,顺利进行迁移工作。

另外,由于DI是完全独立的,因此不需要使用angular2/upgrade的UpgradeAdapter来进行复杂的升级和降级,只需测试正在进行过渡的Angular 2代码即可。
在angular-http-harness的测试代码中,我们实际上使用了Angular 1和Angular 2的服务,并分别在它们的DI机制中进行了测试。值得一提的是,我使用了我自己制作的angular2-testing-micro来编写这些测试代码,这使得可以在karma + mocha + power-assert的环境中同时测试Angular 1和Angular 2。

总结

虽然完全是自家库的宣传,但要推广Angular 2,不可避免地需要解决从Angular 1迁移的问题。特别是对于规模较大的应用程序,需要一种逐步、部分性地迁移而不停止当前应用程序的开发的方法。

尽管angular2/upgrade很有用,但强行在Angular 2中调用Angular 1的代码或者反过来,往往会遇到意想不到的行为问题。

通过像angular-http-harness这样对代码共享和DI输入点进行分离,可能会更顺利地完成迁移,甚至比使用angular2/upgrade更好。

希望大家的Angular 2迁移工作能够变得更轻松一些。:)

广告
将在 10 秒后关闭
bannerAds