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.jcenterRepoaddSbtPlugin(“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 stream或Monix 。 首先要做的是将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


http://www.taodudu.cc/news/show-5408102.html

相关文章:

  • SQL学习(组合查询)
  • Elasticsearch 中 bool组合查询(must 和 should 组合)
  • Vue动态查询条件-Vue动态查询规则-Vue多条件分组组合查询-递归组件(一):前端
  • SQL必需掌握的100个重要知识点:组合查询
  • 集客无线漫游之1——Hyper-V安装x86版集客AC
  • ASP.NET毕业设计 C#高校档案数字化管理系统的设计与实现-王翔-专题视频课程
  • 档案数字化建设-数字档案室建设方案-数字档案管理系统平台建设方案
  • 用计算机管理人员档案属于数据处理,高校档案信息化建设的若干思考
  • 馆藏档案数字化加工:古籍爱好者的福利
  • 具有信息数字化功能的计算机硬件,数字化档案信息安全管理策略论文
  • 面试技巧 简历制作(智联、word
  • Unity3D手游开发日记(10) - 资源打包的一些思考
  • NuGet 的打包教程,使用UI工具 NuGetPackageExplorer 进行打包,处理包的依赖项
  • webpack 分离css html,webpack分离css并单独打包的方法
  • gitbook打包镜像
  • html5 clipboard 兼容,webpack打包clipboard在页面中报错
  • eclipse java 64下载_Eclipse最新版下载_Eclipse 64位官方正式版下载4.8.0 - 系统之家
  • webpack如何将css文件分离的,详解webpack分离css单独打包
  • Java html转pdf批量生成打包zip浏览器下载到客户端
  • py2exe打包python_Python使用py2exe打包程序介绍
  • webpack分离css单独打包
  • 打包python程序_py2exe打包python程序
  • webpack 打包html中css样式如果处理,webpack中单独打包css样式
  • 如何将一个html网页打包,webpack分离css单独打包的方法
  • 软件测试标准
  • 论文解读:Factual Probing Is [MASK]: Learning vs. Learning to Recall
  • react获取url上面参数
  • 计算测试集precision、recall、f1-score
  • scikit-learn:打印分类报告,求准确率、精确率、召回率、F1值等指标
  • Firefox火狐浏览器报错:无法连接到 reCAPTCHA 服务

idea 编写scala_在Scala中编写Angular服务相关推荐

  1. python编写ATM类_Python中编写类的各种技巧和方法

    有关 Python 内编写类的各种技巧和方法(构建和初始化.重载操作符.类描述.属性访问控制.自定义序列.反射机制.可调用对象.上下文管理.构建描述符对象.Pickling).你可以把它当作一个教程, ...

  2. python编写代码_用 Python 编写干净、可测试、高质量的代码

    用 Python 编写干净.可测试.高质量的代码 Noah Gift 2010 年 12 月 20 日发布 简介 编写软件是人所承担的最复杂的任务之一.AWK 编程语言和 "K and R ...

  3. 【未完成】[Spark SQL_2] 在 IDEA 中编写 Spark SQL 程序

    0. 说明 在 IDEA 中编写 Spark SQL 程序,分别编写 Java 程序 & Scala 程序 1. 编写 Java 程序 待补充 2. 编写 Scala 程序 待补充 转载于:h ...

  4. Spark官方文档——本地编写并运行scala程序

    快速开始 本文将介绍如何用scala.java.python编写一个spark单击模式的程序. 首先你只需要在一台机器上成功建造Spark:做法: 进入Spark的根目录,输入命令:$ sbt/sbt ...

  5. 好程序员大数据教程:SparkShell和IDEA中编写Spark程序

    好程序员大数据教程:SparkShell和IDEA中编写Spark程序,spark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用Scala编写Spa ...

  6. 启动Spark Shell,在Spark Shell中编写WordCount程序,在IDEA中编写WordCount的Maven程序,spark-submit使用spark的jar来做单词统计

    1.启动Spark Shell spark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用scala编写spark程序.要注意的是要启动Spark-S ...

  7. python使用spark_如何在Python中编写简单代码,并且速度超越Spark?

    全文共3482字,预计学习时长7分钟 如今,大家都在Python工具(pandas和Scikit-learn)的简洁性.Spark和Hadoop的可扩展性以及Kubernetes的操作就绪之间做选择. ...

  8. python 字节流分段_如何在Python中编写简单代码,并且速度超越Spark?

    全文共 3482字,预计学习时长 7分钟 如今,大家都在Python工具(pandas和Scikit-learn)的简洁性.Spark和Hadoop的可扩展性以及Kubernetes的操作就绪之间做选 ...

  9. 使用Scala语言编写Spark应用程序实现数据去重

    使用Scala语言编写Spark应用程序实现数据去重 一.题目需求 二.建立目录结构 (一)创建 sparkapp4 文件夹并切换 (二)创建 data 文件夹(存放A.txt B.txt) (三)创 ...

最新文章

  1. LIVE555再学习 -- OpenRTSP 源码分析
  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)
  3. php数组修改键值,php数组中子数组如何修改键值
  4. 并查集(Union-Find-Set)简洁而高效地处理连通分量的查询与合并
  5. 彻底搞懂 JS 中 this 机制
  6. 2020年中国职业教育行业白皮书
  7. 数据结构与算法分析(八)——BFS算法
  8. linux新漏洞,「漏洞通告」Linux Kernel 信息泄漏权限提升漏洞(CVE-2020-8835)
  9. 显卡排行榜天梯图2022年9月 笔记本显卡排行榜天梯图2022
  10. Blender - Shrinkwrap - 更方便的制作贴合模型的表面来建模
  11. 心灵的吟唱——读《湖海诗情录》
  12. 【金猿产品展】北森一体化人才管理云平台:让中国企业拥有世界领先的人才管理能力...
  13. android多屏幕多分辨率的一些概念
  14. 获取当前位置的经度纬度
  15. 华栖云联合阿里云发布“云上电视台” 实现媒体云端采编播存管
  16. PDF文件如何转JPG图片?三种方法教你快速转换
  17. Linux内核安装后reboot选择,Linux内核配置选项 参考(3)
  18. c语言将矩形分成多个小正方形,蓝桥杯练习算法题(矩形切割成正方形)
  19. wxPython中XRC文件i18n示例
  20. Cesium|xt3d旋转椎体

热门文章

  1. Mystring类实现运算符重载
  2. java 加背景颜色_Java 给Word文档添加背景颜色
  3. 《Adobe InDesign CS5中文版经典教程》—第1课复习
  4. Matlab 遗传算法优化BP神经网络
  5. Node.js Web开发_设置Node.js(1)
  6. STM32CubeMX新建Project、下载库
  7. 边缘计算网关在水文监测系统中提供多功能应用
  8. IOS端K线系列之K线、OHLC线、分时线基础知识
  9. 【论文笔记】Remote Sensing Image Change Detection with Transformers
  10. SQL分类和命名规范