idea 编写scala_在Scala中编写Angular服务

idea 编写scala

Those following my blog posts know that I like to take Scala everywhere. This time, let us write Angular services in Scala.

那些关注我博客文章的人都知道我喜欢把Scala带到任何地方 。 这次,让我们在Scala中编写Angular服务。

If you don’t know Angular, it’s a frontend web framework developed by Google in TypeScript, similar to React or Vue. It is a component based framework, and to each component is associated a TypeScript class aiming to control what the HTML component must do. These classes can use services. A service is simply another (usually global) instance of a TypeScript class, either with plenty of facility methods (for example for making http calls), or with global object used to pass information from one component to another.

如果您不了解Angular,它是Google在TypeScript中开发的前端Web框架,类似于React或Vue。 它是一个基于组件的框架,并且与每个组件相关联的TypeScript类旨在控制HTML组件必须执行的操作。 这些类可以使用服务。 服务只是TypeScript类的另一个(通常是全局的)实例,它具有大量的便利方法(例如,用于进行http调用),或者具有用于将信息从一个组件传递到另一个组件的全局对象。

Our goal today is to discover how one can create and use Angular services in Scala. Using Scala.js, we can compile our Scala code into plain old JavaScript, and export some of our classes to be used, precisely, by the JS world. Let us get started.

我们今天的目标是发现人们如何在Scala中创建和使用Angular服务。 使用Scala.js,我们可以将Scala代码编译成普通的旧JavaScript,并导出我们的一些类,以供JS世界精确使用。 让我们开始吧。

TLDR: If you want to jump right into the action, you can head over the accompanying repo. Commits in the repo follow along this article. The master branch shows the final version.

TLDR:如果您想直接进行操作,可以转到随附的repo 。 回购中的提交遵循本文。 master分支显示最终版本。

设置项目 (Setup the project)

In order for everything to work properly, we simply need a bunch of plugins for managing the project. There are basically three things that we need to do: telling TypeScript what are the types that we are going to provide it, manage the npm dependencies that we want to use, and tell Scala what are the types that exist in JS/TS in the dependencies that we use. Luckily for us, there are exactly three plugins to do just that, to be added inside `project/plugins.sbt`:

为了使一切正常工作,我们只需要一堆用于管理项目的插件即可。 我们基本上需要做三件事:告诉TypeScript我们将要提供的类型是什么,管理我们要使用的npm依赖关系,以及告诉Scala JS / TS中存在的类型是什么。我们使用的依赖项。 对我们来说幸运的是,恰好有三个插件可以做到这一点,可以添加到`project / plugins.sbt`里面:

addCompilerPlugin(“org.scalameta” % “semanticdb-scalac” % “4.3.10” cross CrossVersion.full)
scalacOptions += “-Yrangepos”/** Explicitly adding dependency on Scala.js */
addSbtPlugin(“org.scala-js” % “sbt-scalajs” % “1.1.1”)/** Plugin for generating TypeScript declaration file. */
resolvers += Resolver.jcenterRepo
addSbtPlugin(“eu.swdev” % “sbt-scala-ts” % “0.9”)/** Plugin for generating Scala.js facades from TypeScript declaration file. */
resolvers += Resolver.bintrayRepo(“oyvindberg”, “converter”)
addSbtPlugin(“org.scalablytyped.converter” % “sbt-converter” % “1.0.0-beta18”)/** Plugin for managing npm dependencies. */
addSbtPlugin(“ch.epfl.scala” % “sbt-scalajs-bundler” % “0.18.0”)

And now we can simply enable all of these, together with some barebones configuration, in our `build.sbt`:

现在我们可以在build.sbt中简单地启用所有这些以及一些准系统配置:

name := “AngularServices”
version := “0.1”
scalaVersion := “2.13.2”/** npm module will have version “0.1.0” */
scalaTsModuleVersion := (_ + “.0”)/** Enabling ScalaJS */
enablePlugins(ScalaJSPlugin)/** Enabling ScalaTS */
enablePlugins(ScalaTsPlugin)/** Enabling Scalably typed, with scala-js-bundler */
enablePlugins(ScalablyTypedConverterPlugin)

We are all set to start creating a JS module for Angular.

我们都准备开始为Angular创建JS模块。

首次服务 (A first service)

One of the strong suit of Scala is its standard collection library. For example, the native JS Array api has no method for taking distinct elements in the array. Let us fix that. Here is a simple implementation which does that (to be put into src/main/scala/angular/ArrayEnhanced.scala):

Scala的强项之一是其标准收藏库。 例如,本机JS Array api没有用于获取数组中不同元素的方法。 让我们解决这个问题。 这是一个简单的实现方法(放入src/main/scala/angular/ArrayEnhanced.scala ):

Well, this came for free. That’s the power of Scala. Let us now generate the JavaScript and the TypeScript declaration file by running the sbt command `scalaTsFastOpt`. After it finishes, you can go have a look into target/scala-2.13/scalajs-bundler/main/angularservices-fastopt.d.ts and you’ll see … nothing! That’s right, because we didn’t actually tell Scala to export this class, nor its members, to the JS world. This is easily done by adding the two annotations to the class:

好吧,这是免费提供的。 这就是Scala的力量。 现在让我们通过运行sbt命令`scalaTsFastOpt`来生成JavaScript和TypeScript声明文件。 完成后,您可以查看一下target/scala-2.13/scalajs-bundler/main/angularservices-fastopt.d.ts ,您将看到……一无所有! 没错,因为我们实际上并没有告诉Scala将此类或其成员导出到JS世界。 通过在类中添加两个注释,可以轻松完成此操作:

Issuing the command again, the content of the declaration file is now

再次发出命令,声明文件的内容现在为

Note: the careful reader maybe asked himself why the type of f in the distinctBy method was the weird looking js.Function1[A, B]instead of A => B. This is because the type A => Bis a Scala function, and pure Scala objects do not enter the JS world. Hence, if we had asked for f: A => B, it would have been impossible for JS to give us the correct argument.

注意:细心的读者可能会问自己:为什么distinctBy方法中f的类型看起来js.Function1[A, B]奇怪的js.Function1[A, B]而不是A => B 这是因为类型A => BScala函数,并且纯Scala对象不会进入JS世界。 因此,如果我们要求f: A => B ,那么JS不可能为我们提供正确的参数。

添加Angular项目 (Adding the Angular project)

Until now, we didn’t do anything specifically related to Angular. Let us do that now. We are going to add an Angular project within the Scala project directory, into `webapp` directory. To that end, we go to `webapp` directory and issue (outside sbt), the command ng new FromScalaWithLove(I chose not to add angular routing and I chose CSS for styling, as we won’t use that.) We can safely delete the content of the app.component.html file, and replace it with

直到现在,我们还没有做任何与Angular相关的事情。 现在让我们这样做。 我们将在Scala项目目录中的Angular项目中添加到webapp目录中。 为此,我们转到“ webapp”目录并发出命令(在sbt之外),执行ng new FromScalaWithLove命令(我选择不添加角度路由,并选择CSS进行样式设置,因为我们不会使用它。)删除app.component.html文件的内容,并将其替换为

<h1>From Scala, with love</h1>

Issuing ng servein the Angular project FromScalaWithLove, and heading to localhost:4200 should make this title appear.

在Angular项目FromScalaWithLove发布ng serve ,并前往localhost:4200应该会显示此标题。

使用我们的Scala服务 (Using our Scala service)

The first thing is to copy paste the files in target/scala-2.13/scalajs-bundler/main into webapp/FromScalaWithLove/node_modules/scala-module. That will make our compiled JS code, together with the type definitions, available to TypeScript. And in app.component.ts, we can add the lines

第一件事是将target/scala-2.13/scalajs-bundler/main的文件复制粘贴到webapp/FromScalaWithLove/node_modules/scala-module 。 这将使我们的编译后的JS代码以及类型定义可用于TypeScript。 在app.component.ts ,我们可以添加以下行

Saving the file should make Angular recompile and refresh the page. Ew, doing this gratified us with an unfriendly `ERROR NullInjectorError`. This makes sense because we never tell the Dependency Injection (DI) mechanism of Angular to take care of our class. This is easily fixed by adding the ArrayEnhanced type inside the providers array in the app.module.ts file. Saving again should make the error disappear.

保存文件应使Angular重新编译并刷新页面。 哎呀,这样做使我们感到不满意,出现了一个不友好的“ ERROR NullInjectorError”。 这是有道理的,因为我们从不告诉Angular的依赖注入(DI)机制来照顾我们的类。 通过在app.module.ts文件中的providers数组内添加ArrayEnhanced类型,可以轻松解决此问题。 再次保存将使错误消失。

We can now happily use the ArrayEnhanced service, for example by adding these lines inside the constructor of the app-component:

现在,我们可以愉快地使用ArrayEnhanced服务,例如通过在app-component的构造函数中添加以下行:

完善开发经验 (Polishing the dev experience)

Having to copy-paste the compiled files inside Angular node modules is a tiny bit annoying. We want to automate this process. This is simply done by adding the following lines to the build.sbt file:

必须将已编译的文件复制粘贴到Angular节点模块中有点烦人。 我们要使这个过程自动化。 只需在build.sbt文件中添加以下几行即可完成:

After reloading sbt, we can issue the makeModule command, which will copy-paste everything properly. Note that in an actual setup, we would like something a bit more fine tuned than hard-coded paths. For now, however, it will do.

重新加载sbt之后,我们可以发出makeModule命令,它将正确复制粘贴所有内容。 请注意,在实际设置中,我们需要比硬编码路径更精细的东西。 但是,到目前为止,它仍然可以。

拥抱RxJS (Embracing RxJS)

The Angular ecosystem makes heavy use of the FRP library RxJS. An Angular user will then most likely expect a service (with asynchronous behaviour) to return Observables instead of, for example, promises. In order to do that, we once again need to change the build.sbt file, in order to add the npm dependency that we want. In this case, `rxjs`. For the sake of speed, we will also tell our project to use yarn instead of npm. This is done by adding the following lines:

Angular生态系统大量使用了FRP库RxJS。 然后,Angular用户最有可能期望服务(具有异步行为)返回Observables而不是例如promises。 为此,我们再次需要更改build.sbt文件,以便添加所需的npm依赖项。 在这种情况下,`rxjs`。 为了提高速度,我们还将告诉我们的项目使用yarn而不是npm。 通过添加以下行来完成此操作:

Compile / npmDependencies ++= Seq(“rxjs” -> “6.4.0”)
useYarn := true

(You might want to clean first in sbt in order to avoid some weird shenanigans.) Now you can reload and kick ScalablyTyped off by issuing compile. This is going to take quite some time (probably 2 to 5 minutes), because all the TypeScript definitions have to be compiled into Scala.js facades. But don’t worry, this is only a one time process.

(您可能希望先在sbt中进行clean ,以避免出现一些奇怪的恶作剧。)现在,您可以通过发出compile reload并启动ScalablyTyped。 这将花费相当长的时间 (可能需要2到5分钟),因为所有TypeScript定义都必须编译成Scala.js外观。 但是不用担心,这只是一次过程。

We can now create a Scala class which will expose an Rx observable for Angular to use. Let us start with something very modest:

现在我们可以创建一个Scala类,该类将公开可观察到的Rx以供Angular使用。 让我们从一个非常谦虚的东西开始:

Issuing the makeModule command should now create a declaration file containing (among others)

发出makeModule命令现在应该创建一个声明文件,其中包含(以及其他)

Since this command automatically copy-paste into Angular’s node module directory, the shiny new EmitRxObservable service will be available immediately. Don’t forget to register it in the app module providers, though.

由于此命令会自动复制粘贴到Angular的节点模块目录中,因此闪亮的新EmitRxObservable服务将立即可用。 不过,请不要忘记在应用程序模块提供程序中注册它。

Note: you will likely hit the following error:

注意:您可能会遇到以下错误:

ERROR in node_modules/scala-module/angularservices-fastopt.d.ts(9,7): error TS1086: An accessor cannot be declared in an ambient context.

which comes from the fact that the interfaced exposed our Scala def as a get accessor. This is “solved” by adding the compilerOption `”skipLibCheck”: true` in `tsconfig.json`. I am not a TypeScript aficionado, so there is perhaps something better to do…

这是因为该接口将我们的Scala def公开为get访问器。 通过在tsconfig.json中添加编译器选项“ skipLibCheck”:true来“解决”。 我不是TypeScript迷,所以也许有更好的事情要做...

We can now happily consume our service by adding the emitRx: EmitRxObservable to the constructor of the app-component, and for example the line

现在,我们可以通过在app-component的构造函数(例如该行)中添加emitRx: EmitRxObservable来愉快地使用我们的服务

emitRx.naturalNumbers.forEach((e) => console.log(e));

in the constructor. Upon reload, the console should show the natural numbers getting printed.

在构造函数中。 重新加载后,控制台应显示要打印的自然数。

请添加更多Scala! (More Scala, please!)

Up until now, we didn’t really do any Scala. We merely used some JavaScript in disguised, but Scala has a lot to offer. For example, it is very good at manipulating data.

到目前为止,我们实际上并没有做任何Scala。 我们只是伪装使用了一些JavaScript,但是Scala提供了很多东西。 例如,它非常擅长处理数据。

We can define a model User, to be used by TypeScript in the project, directly from Scala. This will be a case class with its member exported:

我们可以直接从Scala定义一个模型User ,供项目中的TypeScript使用。 这将是一个案例类,其成员已导出:

We add a facility method maybeDateOfBirth to be used inside Scala, as Option[A] is more Scala friendly than A | undefined. However, even if this method will exist in TS (because we export all members), it won’t be usable since an Option is a pure Scala type, hence opaque. More precisely, it will be usable but TS will not be able to do anything with the returned object, except carrying it along and possibly pass it back to a Scala.js function. But TypeScript will be able to create instances of User (since it knows all the types of the constructor), and we can therefore ask for them in a Scala service. One example is done below:

我们添加了一种在Scala内部使用的工具方法maybeDateOfBirth ,因为Option[A]A | undefined更易于Scala友好A | undefined A | undefined 。 但是,即使此方法将在TS中存在(因为我们导出所有成员),但由于Option是纯Scala类型(因此是不透明的),因此将无法使用。 更准确地说,它将可用,但TS将无法对返回的对象执行任何操作,除非将其携带并可能将其传递回Scala.js函数。 但是TypeScript能够创建User实例(因为它知道构造函数的所有类型),因此我们可以在Scala服务中要求它们。 下面是一个示例:

And from TS, this can be used by doing

从TS可以通过以下方式使用

This shows a tiny bit of what is possible doing Scala: we can define models, let TypeScript instantiate them, and use them as regular Scala objects. The only thing that we need to be careful about is to ask from, and return to, TypeScript, only stuff that it understands.

这显示了执行Scala的可能性的一点点:我们可以定义模型,让TypeScript实例化它们,并将其用作常规的Scala对象。 我们唯一需要注意的事情就是询问TypeScript,然后再返回它,了解它。

让我们疯狂吧 (Let’s go crazy)

Scala also has a gigantic ecosystem with high quality libraries. There is no reason we shouldn’t use them for our Angular projects!

Scala还拥有一个庞大的生态系统,其中包含高质量的库。 没有理由我们不应该在我们的Angular项目中使用它们!

Let us imagine this use case: you are creating a dashboard of some sort, and you need to download a certain amount of data. You don’t want to download everything at once. You are then given a list of indices [0, 1, …, n-1]and you need to make a call for each of these. However, you know that some of them will take longer than others to be processed by your backend, so you don’t want to have these guys be a bottleneck. Also, sometimes your calls fail for some reason (not that often, but it happens) and in these cases you would like to retry twice with some back-off.

让我们想象一下这个用例:您正在创建某种仪表板,并且需要下载一定数量的数据。 您不想一次下载所有内容。 然后,您会得到一个索引列表[0, 1, …, n-1] ,您需要为每个索引进行调用。 但是,您知道它们中的一些将比其他人花费更长的时间由您的后端处理,因此您不想让这些人成为瓶颈。 另外,有时您的呼叫由于某种原因而失败(不是很经常,但它确实发生了),在这种情况下,您希望重试两次并进行一些补偿。

Ultimately, this is what you want to do:

最终,这是您要执行的操作:

  • make n http calls to your backend,

    对您的后端进行n次http调用,
  • always 3 of them concurrently

    总是同时三个
  • retry twice those who fail,

    重试失败者两次,
  • if, despite the two retries, one call still fail, the whole process should fail,

    如果尽管两次重试,一个呼叫仍然失败,则整个过程应该失败,
  • be able to track the progress,

    能够跟踪进度,
  • return an observable which will emit once an array with the result of the n calls, in such a way that the j-th element is the result of mapping j, and

    返回一个observable,它将发出一次带有n个调用结果的数组,以使第j个元素是映射j的结果,并且
  • give the user the possibility to cancel the process before completion.

    使用户可以在完成之前取消该过程。

Good news, this is going to be piece of cake!

好消息,这将是小菜一碟!

We are going to use the ZIO library for that. Other good choices could be AKKA stream or Monix. The first thing to do is to add the ZIO dependency to our project. Add the following line to the build.sbt file:

我们将为此使用ZIO库。 其他好的选择可能是AKKA streamMonix 。 首先要做的是将ZIO依赖项添加到我们的项目中。 将以下行添加到build.sbt文件:

libraryDependencies += “dev.zio” %%% “zio” % “1.0.0-RC21–2”

We will also need the implementation of the comprehensive java.time library for Scala.js, available via

我们还需要实现java.time的全面java.time库的实现,可通过以下途径获得

libraryDependencies += “io.github.cquiroz” %%% “scala-java-time” % “2.0.0"

功能签名 (Function signature)

The function that we are going to expose to TypeScript will have the following signature:

我们将公开给TypeScript的函数将具有以下签名:

where program argument is thought of as an asynchronous observable emitting only once an element of type U. We could also ask for a function returning a js.Promise. We choose the Observable type because it is the one returned by Angular’s `HttpClient`, for example. Note that we only need to export the members of the CompletionState class, because TypeScript never needs to create an instance. It is only required that it understands the ones we are going to give back.

其中program参数被视为异步可观察对象,仅发出一次类型为U的元素。 我们还可以要求一个返回js.Promise的函数。 我们选择Observable类型,因为它是Angular的HttpClient返回的一种。 注意,我们只需要导出CompletionState类的成员,因为TypeScript不需要创建实例。 仅要求它了解我们将要回馈的内容。

从Rx可观察到ZIO效果 (From Rx Observable to ZIO effect)

We need to turn this program function into a ZIO effect that we are going to use afterwards. The program assumes that the returned observable might fail, so we need to take that into account. ZIO has us covered and has the function effectAsync to do just that:

我们需要将此program功能转换为ZIO效果,稍后再使用。 该程序假定返回的observable可能失败,因此我们需要考虑到这一点。 ZIO涵盖了我们,并具有effectAsync函数来做到这一点:

This function thus lifts an observable returning a U into a ZIO effect that might fail with a js.Error, and might succeed with a U. Note that you could very well preserve the fact that in TypeScript, an error can really be “anything”. In that case, we would have asked the ZIO effect to fail with a js.Any instead of js.Error.

因此,此函数可以将U提升为ZIO效果,这种可观察性可能会因js.Error而失败,而可能因U而成功。 请注意,您可以很好地保留以下事实:在TypeScript中,错误实际上可能是“任何错误”。 在那种情况下,我们会要求ZIO效果以js.Any而不是js.Error

重试政策 (The retry policy)

We decided to allow each program to fail a certain number of times. In ZIO, you need to provide a “retry policy” describing the rules to follow in the retry. We can build a retry policy that fits our needs by doing

我们决定允许每个程序失败一定次数。 在ZIO中,您需要提供“重试策略”,以描述重试中要遵循的规则。 我们可以通过制定符合我们需求的重试政策

If the reader is not familiar with ZIO and wonders why this thing does what we want, they can head over here.

如果读者对ZIO不熟悉,并且想知道为什么这件事能满足我们的需求,他们可以前往这里

全球执行计划 (The global execution plan)

The last ZIO piece is a pure function taking the inputs from TS, and a bunch of small helper ZIO effect that are going to be actually built by using Rx Observables. Here is the function

ZIO的最后一部分是一个纯函数,它从TS接收输入,并使用Rx Observables实际构建一堆小助手ZIO效果。 这是功能

The program argument is the program provided by TS, lifted to ZIO. The nextProgress effect will notify that a new program has finished. The two effects complete and fail happen at the end, the former when the whole thing succeeds and the latter when it fails. As we see, the implementation is pretty straightforward. The funny symbol <* means that the right effect will be executed after the left one, but its result will be discarded (similar to Rx tap operator).

program参数是TS提供的程序,并提升为ZIO。 nextProgress效果将通知新程序已完成。 两种效果completefail发生在最后,前者在整个过程成功时发生,后者在失败时发生。 如我们所见,实现非常简单。 有趣的符号<*表示将在左效果之后执行右效果,但其结果将被丢弃(类似于Rx tap运算符)。

通往JS世界的桥梁 (The bridge to JS world)

We are now ready to implement our function. We create observables for ingesting the progress and the output, and we lift that to ZIO. We then run the program as a cancellable future, and expose a JavaScript function to cancel it. Here is the full implementation:

现在,我们准备实现我们的功能。 我们创建可观察的对象来获取进度和输出,并将其提升到ZIO。 然后,我们将程序作为可以取消的将来运行,并公开一个JavaScript函数以将其取消。 这是完整的实现:

And that is all. The nice thing that we get from this is that our execution function is pure and can easily be tested. The Scala compiler is also able to ensure us that the global program will never fail. That means that, from TS’ side, we can be certain that the only errors happening will be the ones coming from the input programs, or the TaskCancelledError in the event that TS cancels it.

仅此而已。 我们从中得到的好处是我们的execution函数是纯函数,可以轻松进行测试。 Scala编译器还可以确保我们全局程序永远不会失败 。 这就是说,从TS的角度来看,我们可以确定发生的唯一错误将是来自输入程序的错误,或者如果TS取消了该错误,则可能是TaskCancelledError

使用它 (Using it)

We can now use our powerful function from Angular. The interested reader will find in the repo an integration with Angular UI. Below, we simply mention a usage with the console.

现在,我们可以使用来自Angular的强大功能。 有兴趣的读者可以在回购中找到与Angular UI的集成。 下面,我们仅提及控制台的用法。

Let us write a “dummy” program simulating an asynchronous computation:

让我们编写一个模拟虚拟计算的“虚拟”程序:

This program returns the input one second later, failing with probability 0.1. It prints the input in case of success, and warn “boom” the input in case of failure. Injecting an instance of ZIOService in our component, we can for example use our function like this:

此程序一秒钟后返回输入,失败的概率为0.1。 如果成功,它将打印输入,如果失败,则警告输入信号“动”。 在我们的组件中注入ZIOService的实例,例如,我们可以使用如下函数:

You will be able to see that

您将能够看到

  • elements get printed 3 by 3

    元素以3 x 3打印
  • the progress will be displayed accordingly

    进度将相应显示
  • from time to time, a “boom j” will be displayed, and you will see that the value will be printed after bigger numbers

    有时会显示“动臂j”,您会看到在较大数字后会打印该值
  • the result array printed at the end is well ordered, as expected.

    如预期的那样,最后打印的结果数组顺序良好。

If you want to see the cancellation in action, you can for example do

如果您想查看取消的实际效果,例如可以

I hope this example demonstrated that Scala, with the help of ZIO, can give you an enormous amount of power via a straightforward interface. It’s now time to draw conclusions from all of this.

我希望这个例子说明Scala在ZIO的帮助下可以通过简单的界面为您提供巨大的功能。 现在该从所有这些结论中得出结论了。

为什么以及何时这样做? (Why and when do this?)

Why should one make Angular Services in Scala? I believe there are a variety of good reasons that I try to discuss below:

为什么要在Scala中制作Angular Services? 我相信有很多很好的原因,我尝试在下面进行讨论:

  • your backend is in Scala. In that case, you will be able to define all your business models for the backend, and expose them to JS/TS to be used immediately. And you can write, in Scala, the type-safe versions of the http calls that you want to make to your backend endpoints. That way, all of your models will be completely in sync, you will be able to have an efficient Scala-to-Scala communication (the ScalaTs repo actually has an example of that).

    您的后端在Scala中。 在这种情况下,您将能够为后端定义所有业务模型,并将它们公开给JS / TS以便立即使用。 您可以在Scala中编写要对后端端点进行的http调用的类型安全版本。 这样,您的所有模型都将完全同步,您将能够进行高效的Scala到Scala的通信( ScalaTs回购实际上就是一个例子)。

  • you need to make very advanced stuff, like above. Using ZIO is only one possible example. But Scala has a lot to offer and is perfectly suited to model complicated business domains.

    您需要制作非常高级的内容,例如上面的内容。 使用ZIO只是一种可能的示例。 但是Scala提供了很多功能,非常适合对复杂的业务领域进行建模。
  • you want to go “all in” and make all your services in Scala, leaving to TypeScript and Angular only the responsibility of the controllers. That way, you can have a nice and clean Scala project, exposing just the right amount of information to your components. You are forced (in a good way) to keep a clear separation of concerns between components and services

    您想“全力以赴”并在Scala中提供所有服务,而仅将控制器的职责留给TypeScript和Angular。 这样,您就可以拥有一个干净整洁的Scala项目,从而向您的组件公开适量的信息。 您被迫(以一种很好的方式)将组件和服务之间的关注点明确分开
  • testing your services will be a lot easier. Scala has amazing test libraries that will allow you to extensively test your services, mocking their concrete implementations if need be.

    测试您的服务将容易得多。 Scala具有出色的测试库,可让您广泛测试服务,并在需要时模拟其具体实现。

注意事项 (Caveats)

There is no such thing as a silver bullet in computer science. This technology is no exception. I can see at least three “drawbacks” that I personally think should not keep you away from choosing it, but you should be aware that they exist.

在计算机科学中,没有什么灵丹妙药。 这项技术也不例外。 我可以看到至少三个“缺点”,我个人认为不应使您选择它,但您应该意识到它们的存在。

  • bundle size: the compiled JavaScript file from Scala.js is one big fat file of easily 4 mb. In today’s fashion of doing single page applications, this should not be too much of a deal. But it certainly means that you shouldn’t do this only for the `distinct` method, as shown above

    包大小:Scala.js编译JavaScript文件是一个很大的胖文件,大小仅为4 mb。 以当今做单页应用程序的方式,这应该没什么大不了的。 但这当然意味着您不应该仅对`distinct`方法执行此操作,如上所示
  • scalably typed typings: scalably typed generates Scala.js facades from TS types for you. Given the nature of TypeScript, they are sometimes a bit cumbersome to work with. If you happen to need a fine tuned facade for one of your libraries, it might be worth writing them by hand. It’s really not that hard

    缩放类型的类型:可缩放类型的类型会为您从TS类型生成Scala.js外观 。 鉴于TypeScript的性质,使用它们有时会有些麻烦。 如果您碰巧需要对其中一个库进行微调的外观,则可能需要手工编写它们。 真的不那么难

  • The ScalaTs plugin is young: the following months, perhaps you will find some very advanced use case that the plugin is not able to handle. No worries, you can still write things down by hand, and raise an issue!

    ScalaTs插件还很年轻:在接下来的几个月中,也许您会发现该插件无法处理的一些非常高级的用例。 不用担心,您仍然可以手工写下来的内容,并提出一个问题!

结论 (Conclusion)

Writing Angular services in Scala is amazing. To me, the advantages largely outweigh the caveats. Especially if your backend is in Scala. The beautiful thing is that most of the above apply not only to Angular, but to any JavaScript/TypeScript project (even node.js ones!).

在Scala中编写Angular服务真是太神奇了。 对我而言,优势大大超过了警告。 特别是如果您的后端在Scala中。 美丽的是,以上大部分内容不仅适用于Angular,而且适用于任何JavaScript / TypeScript项目(甚至是node.js!)。

We did not cover using Angular-Angular services within our Scala services, but it is certainly possible to do so.

我们没有在Scala服务中介绍使用Angular-Angular服务,但确实可以这样做。

Don’t hesitate to give it a try! It is easy to get working with and, who knows, it can be a nice entry point for you into Scala…

不要犹豫,试试看! 易于合作,而且,谁知道,这可能是您进入Scala的一个不错的起点……

翻译自: https://medium.com/@antoine.doeraene/writing-angular-services-in-scala-e83fd308b7c3

idea 编写scala

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值