Denoがコアモジュールをtsからjsに変更したのはなぜですか

最初に理由についてお話ししましょう。根本的な原因は、tsがDenoランタイム用の高性能jsコードを生成できないことです。


jsの置き換えに関する議論は長い間行われてきました。これは、rydocs.google.com / documenによって作成された設計ドキュメントです。

まず、誤解を明確にする必要があります。DenoはTypeScriptをあきらめませんでしたが、Denoは依然として安全なTS / JSランタイムです。

前回Denoがアーキテクチャを調整した後、2つのrustパッケージ(crates)、rusty_v8とdeno_typescriptが追加されました。現在、DenoはC ++ / Cコードを完全に削除しています。各言語の比率はおおよそ次のとおりです。

  • TypeScript:64.7%

  • さび:31.9%

  • JavaScript:1.4%

ご覧のとおり、DenoにはすでにいくつかのJavaScriptコードが含まれています。

Denoのいくつかのコアモジュール(カタログ)を見てみましょう。

  • deno / core:コードは主にrustとjsです

  • deno / cli:すべて錆

  • deno / cli / ops:すべて錆びている

  • deno / cli / js:すべてのタイプスクリプト

  • deno / std / *:ほとんどすべてがtypescriptであり、一部の高性能モジュールはwasm(rust + js)です。

今回は、deno / cli / js / *ディレクトリ内のファイルのみがtsからjsに変更されました。この部分のtsの割合は1/3未満であると直感的に推測します。

理由としては、中国語の翻訳と英語の原文の両方が多少文脈から外れています+推測。コンパイル速度が遅いことは1つの側面ですが、根本的な原因ではありません。rustcのコンパイル速度も非常に遅いですが、生成されたコードは高品質です。Tscは確かに遅いです。tscが高性能のjsコードを生成できる場合、この構築の時間コストは許容範囲内です。しかし現在、tsはDenoランタイム用の高性能jsコードを生成できません。言い換えれば、Denoチームは、tsが高性能のjsコードを生成する方法を見つけられませんでした。

Denoは最新バージョンのtsとv8を使用しており、tsとv8の目標は両方ともstage3です。理論的には、タイプ消去を実行するだけでtsをv8で直接実行できます。当初、Denoチームもそう考えていました。

しかし、tsの実際の使用はそれほど理想的ではありません。

2018年の終わりにDenoのバグの修正を開始しました。2019年に、deno / cli / js / webの下でいくつかのモジュールの保守を開始しました。この時点で、tsの問題が明らかになりました。

たとえば、URLSearchParams 次のコード行をAPIに 追加しました。

一見すると、このコード行は少し不必要です。そのため、PRではURLSearchParams 、WHATWG仕様の記述を繰り返し説明し 、長い間非公開で話し合った。

whatwgのurl仕様に従って、パラメーターは文字列に変換する必要があります。tsを使用してコードを作成する場合、パラメーターは文字列である必要があり、パラメーターの数は1であることが既にデフォルト設定されています。ただし、ユーザーは他のパラメーターを渡すことができます。たとえば、ユーザーがDenoを使用してjsコードを実行する場合、ユーザーはurl.get(1)Denoの動作が準拠していないことを書き込むことができ ます。ユーザーがtsを使用している場合でも、ユーザーはurl.get(1 as any)コードを記述でき ます。

当時の私の提案は、jsを使用してすべてのテストケースを記述し、仕様のすべてのパスを簡単にカバーできるようにすることでした。しかし、ryはまだtsを使用したいので、ユニットテストに多くのas unknown as stringコードを追加しました 

昨年(2019年)の終わりに、私は北京でDeno for ryに対して行ったwpt(Web互換性テスト)レポートを示しました。

私:Webの互換性のためにやるべきことはまだたくさんあります。nodejsのwptをdenoに移植しました。これは、WebAPIを開発するためのガイドとして使用できます。

ry:deno web apiの現在の進捗状況は何ですか?

私:約60%多いです。

ry:ごくわずかです。何か問題はありますか?

私:前回インターネットで話し合ったように、tsにはWebAPIを作成するためのいくつかの癖があります。

現在、Denoは2セットのtsコンパイラを変更しました。1つはdenoの構築時に使用されるため、denoの構築はNode.jsから完全に分離され、もう1つはdeno run コマンドの実行時に使用されるDenoランタイムで使用され ます。さらにdeno doc、Denoにはコマンド用のtsコンパイラの3番目のセットがあり ます。このtsコンパイラは、rust言語を使用して開発されたswcです。swcは型消去のみを行い、静的型チェックは行わず、錆によって発生するため、性能は非常に高いです。

パフォーマンスについて言えば、tsを高性能のjsコードにコンパイルできない理由について話しましょう。

weg仕様に関する上記のtsはすべて、いくつかのハック手法によって回避できます。たとえば、私のPR(存在しないパラメータを並べ替えると削除されますか?URL#2495から)は、クラスの特定の属性をキャストするだけです。仕様で定義されたステップを実装するには、anyの属性のプライベートフィールドにアクセスします。

ただし、パフォーマンスの問題を解決するための非常に良い方法はありません。

引き続き見ていきましょう URLSearchParams。このクラスは次のように定義されています。

export class URLSearchParamsImpl implements URLSearchParams {
  #params: Array<[string, string]> = [];

  constructor(init: string | string[][] | Record<string, string> = "") {
    if (typeof init === "string") {
      this.#handleStringInitialization(init);
      return;
    }

    if (Array.isArray(init) || isIterable(init)) {
      this.#handleArrayInitialization(init);
      return;
    }

    if (Object(init) !== init) {
      return;
    }
...
...

クラスURLSearchParamsImpl定義し 、インターフェースを実装します URLSearchParams

問題はURLSearchParams 、 name 属性にアクセスすると、間違った結果が出力されること "URLSearchParamsImpl"です。これは仕様に準拠していません。URLを仕様に準拠させるには、次のコードを使用する必要があります。

Object.defineProperty(URLSearchParamsImpl, "name", { value: "URLSearchParams" });

V8の場合class URLSearchParams 、このコードのパフォーマンスは、V8の最適な最適化パスを破壊するため、直接書き込みのパフォーマンスよりも低くなり ます。

では、なぜデノは直接書くことができないの class URLSearchParams ですか?これは別の歴史的な問題であり、tsの歴史的な問題です。

Denoはes2019(es10)で書かれています。es3で書かれたNode.jsと比較すると、Denoは非常に現代的です。(現在、Node.jsは部分的にes6にアップグレードされ、es5の一部は保持されています。また、Denoは基本的に完全にes2020にアップグレードされています)。一般的なjsとの非互換性など、jsのレガシー問題は解決されましたが、tsの歴史的なレガシーに遭遇しており、直接定義することはできません class URLSearchParams

当初、Denoのlib.deno.d.tsファイルは.tsソースコードから自動的に生成されましたが、Web APIが追加されるにつれて、この.d.tsの自動生成に問題が発生しました。1つ目は、生成された.d.tsファイルが乱雑でコンパクトではないことですが、使用することはできます。最も深刻な問題は、生成された.d.tsファイルがTypeScriptの組み込みlib。*。d.tsと異なり、多くのtsソースコードがlib.dom.d.tsと同じ宣言ファイルを生成できないことです。

上記のURLSearchParams 例を使用すると 、TypeScriptの組み込みlib.dom.d.tsで、このタイプは次のように定義されます。

interface URLSearchParams {
   ...
}

declare var URLSearchParams: {
    prototype: URLSearchParams;
    new(init?: string[][] | Record<string, string> | string | URLSearchParams): URLSearchParams;
    toString(): string;
};

また、tsは次の宣言ファイルのみを生成できます。

declare class URLSearchParams {
    constructor(init?: string[][] | Record<string, string> | string | URLSearchParams);
    toString(): string;
}

2つは同等である必要があります(私はこれに特に精通していません、そうでない場合は、私に知らせてください)。

.d.tsファイルはes6より前に生成されたため、lib。*。d.tsではクラスは使用されません。

最終的に、Denoは5つのlib。*。d.tsファイルも手動で保守し、上記の URLSearchParamsタイプはlib.deno.shared_globals.d.tsで定義されました。このとき、再度書き込む class URLSearchParams と、.d.tsファイルの型定義が上書きされます。

現在、DenoのWeb APIのほとんどは、このモードを使用しています。このモードはXxxxImplXxxxインターフェイス実装して からリセットする  プロパティを定義 XxxxImpl し nameます。

特定のテクノロジーがxxxの問題を引き起こす場合、このテクノロジーでxxxの問題を解決するか、xxxの問題がない別のテクノロジーを使用します。これは、錆がgoからrustに変更されたときと同じです。goを使用すると、二重のgc問題(gogcとv8gc)が発生します。Denoには、go gcの解決、v8 gcの解決、goの置換、置換の4つの方法があるようです。 v8。実際、goを置き換える方法は1つしかありません。

現在、denoも同様の問題に直面しています。tsはパフォーマンスの問題を伴うjsコードを生成しました。パフォーマンスの問題がどこにあるかはわかっていましたが、tsレベルからは解決できなかったため、「手書きのjsコード」を選択しました。

deno / stdのtsにはこの点でパフォーマンスの問題がないため、tsをjsに置き換える必要はありません。ただし、deno / std / hashには他のパフォーマンスの問題があります。Denoの解決策は、wasmを使用してこのモジュールを書き直すことです。

denoの一部の内部モジュールがtsからjsに変更されましたが、これはtsが機能していないことを意味するのではなく、特定のシナリオにtsが適していないことを意味します。この理由でtsを完全に拒否しないでください。ほとんどのプロジェクトでtsを使用してください。メリットはまだ大きいです。

tsに適さないシナリオがいくつかあると思います。プロトタイプチェーンは頻繁に変更される、属性は実行時に動的に追加する必要があるなどです。

Denoのパフォーマンスの問題は、TypeScriptの組み込みlib.dom.d.tsに特定の仕様と互換性要件を実装する必要があるため、tsが高性能コードを生成できなくなるためです。ほとんどのプロジェクトでは、tsによって生成されたjsコードは依然として非常に優れています。

おすすめ

転載: blog.csdn.net/vCa54Lu0KV27w8ZZBd/article/details/107031323