Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions async.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ JavaScriptの処理系には、現在のシステムのUIを担うレイヤー
CPU速度が問題になることはあまりないとはいえ、コードで処理するタスクの中には長い時間の待ちを生じさせるものがいくつかあります。
例えば、タイマーなどもそうですし、外部のサーバーやデータベースへのネットワークアクセス、ローカルのファイルの読み書きなどは往復でミリ秒、場合によっては秒に近い遅延を生じさせます。
JavaScriptは、そのような時間のかかる処理は基本的に「非同期」という仕組みで処理を行います。
タイマー呼び出しをする次のコードを見て見ます
タイマー呼び出しをする次のコードを見てみます

.. code-block:: ts

Expand Down Expand Up @@ -137,7 +137,7 @@ TypeScriptでは、 ``async`` を返す関数の返り値は必ず ``Promise``

TypeScriptの処理系は、この ``Promise`` の種類と、関数の返り値の型が同一かどうかを判断し、マッチしなければエラーを出してくれます。
非同期処理の場合、実際に動かしてデバッグしようにも、送る側の値と、受ける側に渡ってくる値が期待通りかどうかを確認するのが簡単ではありません。
ログを出して見ても、実際に実行されるタイミングがかなりずれていることがありえます。
ログを出してみても、実際に実行されるタイミングがかなりずれていることがありえます。
TypeScriptを使うメリットには、このように実際に動かすデバッグが難しいケースでも、型情報を使って「失敗するとわかっている実装」を見つけてくれる点にあります。

比較的新しく作られたライブラリなどは最初から\ ``Promise``\ を返す実装になっていると思いますが、そうでないコールバック関数方式のコードを扱う時は ``new Promise``\ を使って\ ``Promise``\ 化します。
Expand Down Expand Up @@ -175,7 +175,7 @@ Node.js標準にもありますし、npmで調べてもたくさんあります

TypeScriptで提供されている ``if`` や ``for`` 、 ``while`` などは関数呼び出しを伴わないフラットなコードなので\ ``await``\ とも一緒に使えます。
``Promise`` やコールバックを使ったコードで、条件によって非同期処理を1つ追加する、というコードを書くのは大変です。
試しに、TypeScriptのPlayGroundで下記のコードを変換してみるとどうなるか見て見ると複雑さにひっくり返るでしょう
試しに、TypeScriptのPlayGroundで下記のコードを変換してみるとどうなるか見てみると複雑さにひっくり返るでしょう

.. code-block:: ts

Expand Down Expand Up @@ -222,7 +222,7 @@ TypeScriptで提供されている ``if`` や ``for`` 、 ``while`` などは関

``Promise`` は「時間がかかる仕事が終わった時に通知するという約束」という説明をしました。
みなさんは普段の生活で、時間がかかるタスクというのを行ったことがありますよね?
味噌汁をガスレンジあたためつつ、ご飯を電子レンジで温め、両方終わったらいただきます、という具合です。
味噌汁をガスレンジで温めつつ、ご飯を電子レンジで温め、両方終わったらいただきます、という具合です。
``Promise`` および、その完了を待つ ``await`` を使えば、そのようなタスクも簡単に実装できます。

.. code-block:: ts
Expand All @@ -243,8 +243,8 @@ TypeScriptで提供されている ``if`` や ``for`` 、 ``while`` などは関
``味噌汁温め()`` と ``ご飯温め()`` は ``async`` がついた関数です。
省略可能ですがあえて返り値に ``Promise`` をつけています。
これまでの例では、 ``async`` 関数を呼ぶ時には ``await`` をつけていました。
``await`` をつけると、待った後の結果(ここでは味噌汁とご飯のインスタンス)が帰ってきます
``await`` をつけないと、 ``Promise`` そのものが帰ってきます
``await`` をつけると、待った後の結果(ここでは味噌汁とご飯のインスタンス)が返ってきます
``await`` をつけないと、 ``Promise`` そのものが返ってきます

この ``Promise`` の配列を受け取り、全部の ``Promise`` が完了するのを待つのが ``Promise.all()`` です。
``Promise.all()`` は、引数のすべての結果が得られると、解決して結果をリストで返す ``Promise`` を返します。
Expand All @@ -256,7 +256,7 @@ TypeScriptで提供されている ``if`` や ``for`` 、 ``while`` などは関
なお、 ``Promise.all()`` の引数の配列に、 ``Promise`` 以外の要素があると、即座に完了する ``Promise`` として扱われます。

類似の関数で ``Promise.race()`` というものがあります。
これは ``all()`` と似ていますが、全部で揃うと実行されるわけではなく、どれか一つでも完了すると呼ばれます。
これは ``all()`` と似ていますが、全部が揃うと実行されるわけではなく、どれか一つでも完了すると呼ばれます。
レスポンスの値は、引数のうちのどれか、ということで、結果を受け取る場合は処理が少し複雑になります。
結果を扱わずに、5秒のアニメーションが完了するか、途中でクリックした場合には画面を更新する、みたいな処理には適しているかもしれません。

Expand Down Expand Up @@ -290,14 +290,14 @@ TypeScriptで提供されている ``if`` や ``for`` 、 ``while`` などは関
)
);

図で見て見ると、この違いは一目瞭然でしょう。
図で見てみると、この違いは一目瞭然でしょう。

.. figure:: images/async/loop.png

``Promise.all()`` が適切ではない場面もいくつかあります。

例えば、外部のAPI呼び出しをする場合、たいてい、秒間あたりのアクセス数が制限されています。
配列に100個の要素があるからといって100並列でリクエストを投げるとエラーが帰って来て正常に処理が終了しないこともありえます
配列に100個の要素があるからといって100並列でリクエストを投げるとエラーが返ってきて正常に処理が終了しないこともありえます
その場合は、並列数を制御しつつ ``map()`` と同等のことを実現してくれる ``p-map`` [#]_ といったライブラリを活用すると良いでしょう。

.. [#] https://www.npmjs.com/package/p-map
Expand Down
2 changes: 1 addition & 1 deletion class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ JavaScriptではまだStage 3の機能ですが、TypeScriptですでに使え
これらの機能は、言語の文化とか、他の代替文法の有無とかで使われ方が大きく変わってきます。

TypeScript界隈では、Angularなどのフレームワークではインタフェースが多用されています。
ユーザーが実装するコンポーネントなどのクラスにおいて、Anguarが提供するサービスを受けるためのメソッドの形式が決まっていて、実装部分の中身をライブラリユーザーが実装するといった使われ方をしています。
ユーザーが実装するコンポーネントなどのクラスにおいて、Angularが提供するサービスを受けるためのメソッドの形式が決まっていて、実装部分の中身をライブラリユーザーが実装するといった使われ方をしています。
``OnInit`` をimplementsすると、初期化時に呼び出されるといった具合です。

継承が必要となるのは実装も提供する必要がある場合ですが、コードが追いかけにくくなるとか、拡張性のあるクラス設計が難しいとかもあり、引き継ぐべきメソッドが大量にあるクラス以外で積極的に使うケースはあまり多くないかもしれません。
Expand Down
6 changes: 3 additions & 3 deletions complex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ JSON(JavaScript Object Notation)
プレーンテキストであり、書きやすく読みやすい(XMLやSOAPと比べて)こともありますし、JavaScriptでネイティブで扱えるため、API通信で使われるデータフォーマットとしてはトップシェアを誇ります。

JSONをパースすると、オブジェクトと配列で階層構造になったデータができあがります。
通信用のライブラリでは、パース済みの状態でレスポンスが帰ってきたりするため、正確ではないですが、このオブジェクト/配列も便宜上、JSONと呼ぶこともあります。
通信用のライブラリでは、パース済みの状態でレスポンスが返ってきたりするため、正確ではないですが、このオブジェクト/配列も便宜上、JSONと呼ぶこともあります。

.. code-block:: ts
:caption: JSONとオブジェクト
Expand All @@ -438,7 +438,7 @@ JSONをパースすると、オブジェクトと配列で階層構造になっ
// 省略可能。通常はnull
// 3つめは配列やオブジェクトでインデントするときのインデント幅
// 省略可能。省略すると改行なしの1行で出力される
const json = JSON.stringfy(smallAnimal, null, 2);
const json = JSON.stringify(smallAnimal, null, 2);

// これは複製されて出てくるので、元のsmallAnimalとは別物
const smallAnimal2 = JSON.parse(json);
Expand All @@ -447,7 +447,7 @@ JSONはJavaScript/TypeScriptのオブジェクト定義よりもルールが厳
たとえば、キーは必ずダブルクオートでくくらなければなりませんし、配列やオブジェクトの末尾に不要なカンマがあるとエラーになります。
その場合はJSON.parse()の中で ``SyntaxError`` 例外が発生します。
特に、JSONを便利だからとマスターデータとして使っていて、非プログラマーの人に、編集してもらったりしたときによく発生します。
あとは、JSONレスポンスを期待しているウェブサービスの時に、サーバー側でエラーが発生して、 ``Forbidden`` という文字列が帰ってきた場合(403エラー時のボディ)にも発生します。
あとは、JSONレスポンスを期待しているウェブサービスの時に、サーバー側でエラーが発生して、 ``Forbidden`` という文字列が返ってきた場合(403エラー時のボディ)にも発生します。

.. code-block:: text
:caption: JSONパースのエラー
Expand Down
6 changes: 3 additions & 3 deletions exception.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ JavaScriptの言語の標準に含まれていない、処理系独自の機能
}
}

よくやりがちなのが、 ``ok`` の確認をしない(ステータスコードが200以外でJSON以外が帰ってきているときに)JSONをパースしようとしてエラーになることです。
よくやりがちなのが、 ``ok`` の確認をしない(ステータスコードが200以外でJSON以外が返ってきているときに)JSONをパースしようとしてエラーになることです。
``404 Not Found`` のときは、ボディが ``Not Found`` というテキストになるので、未知のトークン ``N`` というエラーになります。あとは403 Forbiddenのときには、未知のトークン ``F`` のエラーが発生します。

.. code-block:: text
Expand Down Expand Up @@ -302,7 +302,7 @@ JavaScriptの言語の標準に含まれていない、処理系独自の機能
console.log(e);
}

エラーを発生させるには、 ``Promise`` 作成時のコールバック関数の2つめの引数の ``reject()`` コールバック関数に ``Error`` オブジェクトを渡しても良いですし、
エラーを発生させるには、 ``Promise`` 作成時のコールバック関数の2つめの引数の ``reject()`` コールバック関数に ``Error`` オブジェクトを渡しても良いですし、
``then()`` 節の中で例外をスローしても発生させることができます。

.. code-block:: ts
Expand Down Expand Up @@ -345,7 +345,7 @@ JavaScriptの言語の標準に含まれていない、処理系独自の機能
* 原因: ネットワークエラー
* リカバリー: リトライ

* サーバーにリクエストを送ってみたら400エラーが帰ってきた
* サーバーにリクエストを送ってみたら400エラーが返ってきた

* 原因: リクエストが不正
* リカバリー(開発時): 本来のクライアントのロジックであればバリデーションで弾いていないといけないのでこれは潰さないといけない実装バグ。とりあえずスタックトレースとかありったけの情報をconsole.logに出しておく。
Expand Down
2 changes: 1 addition & 1 deletion function.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

そこで理解できる大きさにグループ化して、名前をつけたものが関数です。関数呼び出しはネストできるので、難しいロジックに名前をつけて関数を作り、それらのロジックを並べたちょっと複雑なタスクを人間の仕事に近い高水準な関数にできます。関数は決まった処理を単純に実行するだけではなく、引数をとって、柔軟に動作させることもできますし、返り値を返すこともできます。

どの程度の分量が適切かはロジックの複雑さによります。単純な仕事を延々と行っている(Reactのコンポーネントのレンダリングなど)であれば、数画面分のコードでもなんとかなるでしょうし、帰って細かく分け過ぎてしまうと、全体像の把握が難しくなります。一方で複雑なロジックだと20行でも難しいかもしれません。
どの程度の分量が適切かはロジックの複雑さによります。単純な仕事を延々と行っている(Reactのコンポーネントのレンダリングなど)であれば、数画面分のコードでもなんとかなるでしょうし、かえって細かく分け過ぎてしまうと、全体像の把握が難しくなります。一方で複雑なロジックだと20行でも難しいかもしれません。

関数の基本形態は以下の通りです。

Expand Down
2 changes: 1 addition & 1 deletion functional.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ JavaScriptで実現できる関数型プログラミングのテクニックは

* ``map()``: 元のデータの各要素に何かしらの加工を行った新しい配列を作る
* ``forEach()``: 元のデータの各要素に対するループを行う
* ``fileter``: 元のデータの書く要素を評価し、選択されたものだけを保持する新しい配列を作る
* ``filter``: 元のデータの書く要素を評価し、選択されたものだけを保持する新しい配列を作る

これは配列の例ですが、複合型の場合に値そのものを書き換えるのではなく、書き換えた別のバージョンを作っていくのがポイントです。
オブジェクト指向はデータと操作が結びついていますが、関数型はデータとそれに対する操作を切り離すと共に、データを複製するという異なったアプローチを取ります。
Expand Down
4 changes: 2 additions & 2 deletions libenv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ package.jsonで手を加えるべきは次のところぐらいですね。
"module": "dist-esm/index.js",
"types": "dist-cjs/index.d.ts",
"scripts": {
"build": "npm-run-all -s build:cjs buid:esm",
"build": "npm-run-all -s build:cjs build:esm",
"build:cjs": "tsc --project . --module commonjs --outDir ./dist-cjs",
"build:esm": "tsc --project . --module es2015 --outDir ./dist-esm"
}
Expand Down Expand Up @@ -158,7 +158,7 @@ package.jsonで手を加えるべきは次のところぐらいですね。

* TypeScriptでライブラリのコードを記述する
* 使う人は普段通りrequire/importすれば、特別なツールやライブラリの設定をしなくても適切なファイルがロードされる。
* 使う人は、別途型定義ファイルを自作したり、別パッケージをインストールしなくても、普段通りrequire/importするだけでTypeScriptの処理系やVisual Stuido Codeが型情報を認識する
* 使う人は、別途型定義ファイルを自作したり、別パッケージをインストールしなくても、普段通りrequire/importするだけでTypeScriptの処理系やVisual Studio Codeが型情報を認識する
* Tree Shakingの恩恵も受けられる

``package.json`` の ``scripts`` のところに、開発に必要なタスクがコマンドとして定義されています。npmコマンドを使って行うことができます。
Expand Down
2 changes: 1 addition & 1 deletion module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ Node.js向けに出力する場合は、 ``import`` と ``export`` を、CommonJ
}

// リネームしてエクスポート
export { favorite as favariteFood };
export { favorite as favoriteFood };

複数のファイル内容をまとめてエクスポート
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
Loading