根据 github 发布的 Octoverse(章鱼宇宙?) 2019 年度开源报告的数据,JavaScript 依然是全球开源社区活跃度最高的编程语言(2018 年也是 JavaScript),同时 Dart 以 532% 的比例成为年度贡献者增长最多的编程语言(2018 年是 Kotlin)。
虽然从总量上来说,Dart 在 Google Trends 上面的热度还不及 JavaScript 以及 TypeScript。但预期在 Flutter 以及后续 Fuchsia 操作系统的强力带货下,Dart 在 2020 年必然会有一波行情。
Dart is a client-optimized language for fast apps on any platform。Dart 从 2.0 版本重启之后强调它针对客户端开发进行的优化。但它一直就自带 Server Side 电池。本文尝试了解 Dart 当前在服务端的发展。
编程语言
作为一个较新的编程语言,Dart 拥有现代的语言特性。
对于熟悉 TypeScript 的同学来说,上手 Dart 进行服务端开发基本上没有什么障碍。而它的事件循环对于熟悉 Node.js event-loop 的同学来说也是非常熟悉。
Dart 比较独特的是它基于 Isolate 的多线程机制。每个 Isolate 拥有独立的内存空间,独立的 event-loop,彼此只基于消息进行通信,因此可以避免一般多线程语言的线程死锁问题。
对于计算密集型的任务,可以新建一个 Isolate 进行非阻塞的执行。Dart 还提供了一个 high level 的 isolate.compute 接口用来在独立的 isolate 中执行计算任务。
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
await client.get('https://jsonplaceholder.typicode.com/photos');
// Use the compute function to run parsePhotos in a separate isolate.
return compute(parsePhotos, response.body);
}
Dart 有独立的 Dart VM,可以通过不同的编译方式支持 JIT 和 AOT。对于追求快速启动单次执行的场景(比如 FaaS)AOT 的启动时间要快得多,而对于长时间运行的服务端应用进程来说,JIT 可以获得更好的运行时性能。此外,通过 dart2js 可以将 Dart 程序编译成 JavaScript 代码,node_interop 这个 package 可以调用 Node.js Core API,最终让 Dart 程序运行在 Node.js 上。
同时由于有 JIT Compiler 的存在,使得 Dart VM 也能支持 hot reload,使 Dart 服务端开发可以拥有不错的本地开发体验。
服务端开发框架
Dart 相比较于 JavaScript 在三方生态上要落后很多,因此采取了更多的自带电池(Battery Included)策略。除了提供 dart:io 这样的底层包支持 HTTP、Socket 的 Server 和 Client 的编写之外,官方也提供了一个类似 connect 的 micro-framework,叫做 shelf,可以胶合各种 middleware 进行请求的处理。
import 'dart:io';
import 'package:args/args.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
const _hostname = 'localhost';
void main(List<String> args) async {
var parser = ArgParser()..addOption('port', abbr: 'p');
var result = parser.parse(args);
var portStr = result['port'] ?? Platform.environment['PORT'] ?? '8080';
var port = int.tryParse(portStr);
if (port == null) {
stdout.writeln('Could not parse port value "$portStr" into a number.');
// 64: command line usage error
exitCode = 64;
return;
}
var handler = const shelf.Pipeline()
.addMiddleware(shelf.logRequests())
.addHandler(_echoRequest);
var server = await io.serve(handler, _hostname, port);
print('Serving at http://${server.address.host}:${server.port}');
}
shelf.Response _echoRequest(shelf.Request request) =>
shelf.Response.ok('Request for "${request.url}"');
但 shelf 并不是一个开箱即用的应用开发框架,配套的中间件也不多,从仓库的更新频率来说不算是积极维护状态。这可以算是大部分 dart 服务端开发框架的现状。目前有限观察到的 star 较多的几个 dart 服务端开发框架比如 aqueduct、angel、jaguar 的活跃度都比较有限(contributor 有限或者更新不频繁),曾经是官方出品的基于 shelf 的 redstone 框架目前也有几年没有更新。
其中 aqueduct 框架利用了 Dart 的 isolate 做了多线程的支持。按照框架描述的理念,aqueduct 希望通过 isolate 实现 erlang actor 的理念。但事实上可能受限于新建 isolate 的开销不低,aqueduct 目前做到的是根据配置(或 CPU 核数)创建若干个 isolate 分别启动 ApplicationIsolateServer 实例用于响应请求,同时通过 ApplicationIsolateSupervisor 进行守护。和我们的 Node.js 框架 Midway 有几分相似。未来相信一定会有框架基于 Isolate 玩出更多可能性。
工具链
受益于官方自带电池的策略,Dart 的官方工具链阵容非常强大。
阶段性感受
以上感受来自对于 Server Side Dart 的初步观察,欢迎有实践经验的同学留言交流。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8