DenoはNode.jsとどこが違うのか超ざっくりまとめ🦕

<img width="150" alt="deno-logo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44264/6f15366d-dcb2-6d33-6ae3-2b25c0d2071c.png">

2020年5月13日、ついにver1.0がリリースされた[Deno](https://deno.land/)。
Node.jsとの違いをざっくりと解説します。

※以下、本記事の内容は[Deno公式マニュアル](https://deno.land/manual)の記述に基づきます

#そもそもDenoって何なの？
DenoはJavaScriptおよびTypeScriptの実行環境です。
V8, Rust, およびTokioによって作られています。

#え、Node.jsがあるじゃん？
Node.jsは2009年に誕生し、すでに10年を超える歴史を有しています。

たとえばNode.jsが生まれたとき、この世にPromiseはありませんでした。
2012年にはTypeScriptが生まれました。

この10年で、JavaScriptを取り巻く環境は大きく変わってしまったのです。

そして2020年。
Node.jsの問題を解決し、よりよい開発環境を提供するため、Node.jsの開発者であるライアン・ダールらの手によって生まれたのがDenoなのです（DenoはNodeのアナグラム）。

#DenoはNode.jsとどこが違うのか
##npmを使いません
モジュールは任意のURLまたはファイルパスからダウンロードされます。

```javascript

import {hoge} from "fuga";
```

というNode.jsでの記述形式は、指定されたモジュールがどこにあるのか特定できないという問題を引き起こしていました。

`fuga` モジュールはNPMサーバにあるのかもしれないし、ローカルの`node_modules`フォルダにあるのかもしれません。

```javascript
import {hoge} from "https://your.domain.com/fuga.ts";
```

とすることで、`fuga`ライブラリの場所は一意に定まります。

またこれは同時に、`package.json`に相当するしかけを必要としないことをも意味します。

URLやファイルパスがそのままバージョンの指定にもなっていれば、わざわざ別ファイルでその依存性情報まで管理する必要はないからです。



##TypeScriptを標準でサポートします
追加のライブラリをインストールすることなく、TypeScriptをコンパイルしてくれます。

コンパイルは自動的に行われるので、コマンドを叩く必要もありません。

##セキュアです
明示的に許可されない限り、denoはネットワーク接続もファイル読み取りもできません。

例として、標準ライブラリとして公開されている`curl.ts`でURLへのアクセスを試してみるとエラーが返ります。

```shell

$> deno run https://deno.land/std/examples/curl.ts https://example.com
error: Uncaught PermissionDenied: network access to "https://example.com/", run again with the --allow-net flag
```

接続許可するドメインを`--allow-net`フラグに設定することで初めて、URLへのアクセスが可能になります。

```shell

deno run --allow-net=example.com https://deno.land/std/examples/curl.ts https://example.com
```

よくわからないNPMパッケージを走らせたら、変なURLに接続されたりファイルシステムを触られたりするのではないか……という恐怖ともこれでおさらばです。

詳細: https://deno.land/manual/getting_started/permissions

##標準テストランナーがあります
`Deno.test`を使えば、ライブラリをインストールすることなくテストを実行できます。

```typescript
Deno.test("Hello deno test", () => {
  const foo: string = "Hello";
  if (foo !== "Hello") {
    throw ("foo should be Hello.");
  }
});
```

アサーションライブラリも用意されています。

```typescript
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
Deno.test("Hello assertion", () => {
  const foo: string = "Hello";
  assertEquals(foo, "Hello");
});
```

実行するときは `deno test [files]` コマンドを叩くだけ。かんたん！


詳細: https://deno.land/manual/testing

## 非同期のアクションはすべてPromiseを返します
Webサーバを記述する場合、Node.jsではこんな感じでしたが

```javascript

var http = require('http');

http.createServer(function (req, res) {
  res.write('Hello World!');
  res.end();
}).listen(8080);
```
出典: https://www.w3schools.com/nodejs/nodejs_http.asp

Denoでは`await`を使ってこんな感じになります。

```javascript

import { serve } from "https://deno.land/std/http/server.ts";
const s = serve({ port: 8080 });
for await (const req of s) {
  req.respond({ body: "Hello World!\n" });
}
```
出典: https://deno.land/std/http

## 予期せぬエラーが発生した場合は"常に"処理を終了します
[Uncaught Exceptions in Node](https://shapeshed.com/uncaught-exceptions-in-node/)などの記事に見られるように、Node.jsでは捕捉できないエラーをどう扱うかは開発者に任せられていました。

処理を終了させてもいいし、もみ消して続行させることもできました。

Denoでは常に処理が終了します。常にです。

#おまけ
Node.jsが抱える問題点、およびDenoが目指すゴールについては、ライアン・ダール自らによる以下のプレゼンテーションを見るとわかりやすいです。
[Node.jsに関する10の反省点 Ryan Dahl - JSConf EU 2018](https://www.youtube.com/watch?v=M3BM9TB-8yA)