async/awaitメモ

参考

Promise chainで書く方法 developer.mozilla.org

Fetch APIについて developer.mozilla.org

async/awaitについて developer.mozilla.org

サンプル github.com

はじめに

明示的にPromise chainで書く方法よりasync/awaitで(見かけ上)同期的に書く方が読みやすいと思うし、そもそもasync/awaitで書く方がスタンダードだと思うので使用方法と典型的なパターンをメモする。

async/awaitの基本

  1. async キーワードを関数の前につける → async キーワードをつけた関数はasync function になる

    async function

    • await キーワードはasync functionの中でしか使えない
    • promiseを返す関数になる

    async function - JavaScript | MDN

  2. async function 内でawait キーワードを置く

    • await キーワードと組み合わせないとasync function の利点が活きてこない
    • await の機能は以下だけ。

      await can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.

    • await キーワードは以下の条件を満たす関数の前に置くことができる。つまり少なくともasync function の前には置くことができる

      • 非同期関数
      • promiseを返す

Promise chainからasync/awaitへの書き換え

基本的には変換可能?thenをすべてなくすことができる。もちろんPromise chainとasync/awaitのハイブリッドでもいい

典型パターン

fetchでデータを取得するasync function

https://github.com/node-fetch/node-fetch

node-fetchを使った例

注意:node-fetch@2.XはCommonJSと互換がある, 3.XはESMモジュール。Lambdaで使う際に引っかかった。node環境で3.Xを使うならpackage.json"type": "module" の追記が必要。

import fetch from 'node-fetch';

// 1.async functionの定義
async function myAsyncFunc() {

    //fetchは非同期関数かつpromiseを返すのでawaitキーワードを置ける
    const response = await fetch('https://api.github.com/users/github'); // Block this line

    if(!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    //ここでもawait必要
    const data = await response.json();
    //処理を実装
    console.log(data);
    //取得したデータを返してもいい
    return data
}

// 2. 1.で定義したasync funcitonを使う
// 戻り値を使う際は、ここでもawaitが必要。myAsyncFuncはasync functionなのでawaitを置ける
// awaitを置かない場合はPromiseが返る
const data = await myAsyncFunc()
.catch(e => {
    console.log('There has been a problem with your fetch operation: ' + e.message);
})

console.log(`Name: ${data.name}`);

並列実行パターン(Promise.all)

よーいドンで並列に非同期関数を実行する場合は、気をつけないと性能劣化する。加えて、Promise.allを使わないとハンドリングできないエラーが発生するそう。

まだこのパターンが必要になったことがないので、必要になった際に追記する。(実際に使うとしたら以下のような例だと思う。)

import fetch from 'node-fetch';

// 1.async functionの定義
async function myAsyncFunc() {

    //fetchは非同期関数かつpromiseを返すのでawaitキーワードを置ける
    const response = await fetch('https://api.github.com/users/github'); // Block this line

    if(!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    //ここでもawait必要
    const data = await response.json();
    //処理を実装
    //console.log(data);
    //取得したデータを返してもいい
    return data
}

const promiseArr = [];
//10個の並列呼び出し
for(let i = 0; i < 10; i++) {
    //ここがポイント。あえてawaitを置かずにPromiseを取得する。
    const p = myAsyncFunc();
    promiseArr.push(p);
}

//Promiseがすべて解決するのをここで待つ
const results = await Promise.all(promiseArr);
console.log(`Length of results: ${results.length}`);
console.log(results);

sliceの定義パターンメモ

Sliceの定義パターンメモ

定義の方法が何種類かあるが、実際に書いてるとき毎回ググったりするのが煩わしいのでまとめる。 パターンは以下の本に記載されていたもの。この本は他にも実際に書いているとどれが正しいのか迷ってしまうようなものをケースごとにパターン分けしてまとめてくれているのでとても参考になる。

Learning Go

適切な定義

  • sliceの拡張(メモリの再確保)する回数を最小化にするように定義する
  • golangでもsliceの内部配列は拡張時に現在の2倍のサイズを確保する

定義パターン

1. var declaration with no assigned value [zero length, nil]

nil sliceを作る。

var data []int
  • length: 0
  • capacity: 0
  • nil

いつ使う?

  • まったくsliceが拡張する必要がないとき。
  • sliceからJSONに変換するときのみ有用

いきなり↑の意味がわからなかった😢

2. slice literal [non-zero length, not nil]

data := []int{2,4,6,8} // numbers we appreciate

いつ使う?

  • 初期値があるとき
  • sliceの値が変わることがないとき

3. make()

必要なsliceのサイズがだいたいわかっているが入る値についてはコードを書いてるときにはわからないとき。プログラム実行時にデータを取得して入れるときとか?この場合はmakeを使う。

これはすなわち以下の#1 or #2のどちらにするかという問題になる

  1. 「makeでnon-zero lengthを指定する」
  2. 「makeでzero lengthを指定する + non zero capacityを指定する」

3-1. slice as buffer [non-zero lenght, not nil]

これは#1

buf := make([]byte, 2048)

いつ使う?

  • sliceをbufferとして使うとき

3-2. non-zero lengthを指定、値の設定はindexを使う [non-zero lenght, not nil]

  • これも#1
  • 要素へのアクセスはindex
  • 注意: この定義の場合appendで要素を追加すると、末尾に追加される。0番目には追加されない
original := []int{1, 2, 3, 4, 5}
double := make([]int, 5)
fmt.Printf("original: %v length: %v, capacity: %v", original, len(original), cap(original))
fmt.Printf("double: %v length: %v, capacity: %v", double, len(double), cap(double))
for i, v := range original {
    double[i] = 2 * v 
}
fmt.Printf("double: %v length: %v, capacity: %v", double, len(double), cap(double))

いつ使う?

  • あるsliceの値を変換した値を入れるsliceを用意するとき

デメリット

  • lengthの指定を間違えると、必要なサイズより大きい場合は無駄なzero valueがsliceの余剰部分に残る、または小さい場合はindex指定でout of rangeでpanicが起きる

3-3. zero lengthを指定、non-zero capacityを指定 [zero length, not nil]

これは#2

a := make([]int, 0, 5)

いつ使う?

  • 上記以外のシチュエーション

メリット

  • 必要なサイズが想定より小さい場合に無駄なzero valueが入らない、逆に大きい場合もindex指定と違ってout of rangeでpanicが起きることもない

結論

goのコミュニティでは3-2派と3-3派で分かれているらしい。 本書では、パフォーマンス的には遅くなる可能性があるが、バグの原因となる可能性があるため安全面から3-3のzero lengthでappendで値を追加していく方を推奨している

// 3-2
x := make([]int, 5) // [0 0 0 0 0] length: 5, capacity: 5
x[0] = 10

// 3-3
y := make([]int, 0, 5) // [] length: 0, capacity: 5
y = append(y, 10)

zero length vs zero length + capacity指定

ちなみにcapacityを指定するメリット capacityを指定していないsliceは0->1->2->4->8と4回拡張している。逆にサイズ指定しているsliceは0回

a := make([]int, 0, 5)
var b []int
fmt.Printf("a: %v length: %v, capacity: %v", a, len(a), cap(a))
fmt.Printf("b: %v length: %v, capacity: %v", b, len(b), cap(b))
for i := 1; i < 6; i++ {
    a = append(a, i)
    b = append(b, i)
}
fmt.Printf("a: %v length: %v, capacity: %v", a, len(a), cap(a))
fmt.Printf("b: %v length: %v, capacity: %v", b, len(b), cap(b))
a: [] length: 0, capacity: 5
b: [] length: 0, capacity: 0
a: [1 2 3 4 5] length: 5, capacity: 5
b: [1 2 3 4 5] length: 5, capacity: 8

Next.jsのpre-renderingメモ

Pre-rendering

By default, Next.js pre-renders every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and SEO.

JavaScript React app Nextjs app
enable ✔️ ✔️
disable ✔️️

Two Forms of Pre-rendering

  • Static Generation is the pre-rendering method that generates the HTML at build time. The pre-rendered HTML is then reused on each request.

  • Server-side Rendering is the pre-rendering method that generates the HTML on each request.

  • Pre-renderingには2つの種類がある
  • page毎に選択できるらしい
  • Static Generationが基本的には推奨される。
    • ビルド時に静的なHTMLを生成してCDNに保持される。
  • 頻繁に更新されるデータを表示するページで、リクエストのたびにページの内容が更新される場合。この場合はServer-side Renderingを使う。または従来のClient-side Renderingとなる。

Static Generation with Data

VSCode設定まとめ

メインエディタをVimからVScodeにしようかなと思ったのでメモ書き

設定同期

自分のgithub accountで同期

Settings Sync in Visual Studio Code

ショートカット

設定

  • alt + s + alt + pでショートカット設定を開いて設定
  • 被っているショートカットの検索は、検索窓の recorded keys に切り替えてショートカットで検索。
    • これでvimコマンドと被っているコマンドも確認できる

デフォルト

  1. User settings: Ctrl + , Command + ,
  2. コマンドパレット: Ctrl + Shift + p Shift + Command + p

その他のデフォルトのショートカット

ユーザー定義

項目 説明 プラグイン ショートカット
grep 全文検索 vscode本体 ctrl + shift + f, command + shift + f
find ファイル名検索 vscode本体 ctrl + p, command + p
ショートカット設定 ショートカットのキーを順番にササっと入力すれば大丈夫。そこまでシビアな入力判定ではない。vimのキーバインディングだとデフォルトのショートカット使えないので変えておく vscode本体 alt + s + alt + o
Terminalトグル Terminal開いていない時は新規に開いてくれる vscode本体 F9
新規Terminal 新規Terminalを開く vscode本体 shift + F9
Markdown preview ehnancedのプレビュー開く Markdown preview ehnanced alt + p
Markdownのテーブル挿入 Markdown preview ehnanced alt + p

基本ムーブ

  1. コマンドパレットを開く
  2. やりたいことを入力してみる
  3. 出てきたコマンドでの設定ボタンでショートカットが設定されていなかったら設定する

Settings

Theme

Darcula Theme https://marketplace.visualstudio.com/items?itemName=rokoroku.vscode-theme-darcula

Vim emulator

制約と誓約により高まるVim

GitHub - VSCodeVim/Vim: Vim for Visual Studio Code

Font

Fira code

GitHub - tonsky/FiraCode: Free monospaced font with programming ligatures

インストールと各種エディターでの設定方法

Home · tonsky/FiraCode Wiki

UI

    "workbench.colorCustomizations": {
        "statusBar.background" : "#0c000b",
    }

Extensions

とりあえず入れてるもの。今後、GoLandもVSCodeに移行しようかなと思うのでそのうちまた増える。

JS

  1. Prettier
  2. Bracket pair colorizer
  3. JavaScript ES6 Code snippets

    ショートカットはREADMEに書いてある

    GitHub - xabikos/vscode-javascript: Contains the code snippets for JavaScript (ES6) development in VS Code editor

  4. Simple React snippets

    ショートカットはREADMEに書いてある

    GitHub - burkeholland/simple-react-snippets: Simple React Snippets for VS Code that you will actually use

Markdown

  1. Markdown Preview Enhanced

    Markdown Preview Enhanced

  2. Markdown All in One ボルドとかイタリックとかよくあるショートカット使えるようになるはずだが、Windowsは、デフォルトがctrlを使うのでvimキーバインディングだと使えない。テーブル挿入くらいのために使う

  3. Markdown Emoji
    VSCodeMarkdown プレビューに:emoji: syntaxのサポート追加 👍

  4. :emojisense: emojiのサジェスト 🥇 🔥 🐈 🎸 🎾

Debug

組み込みのデバッガーで直接デバッグできるらしい。これはまた別記事でまとめる。

Types assertions

Types assertions

interface typeの変数が実際に持っているtypeをチェックする

記法

// 戻り値2個パターン
t, ok := i.(T)

// 戻り値1個パターン
t := i.(T)

戻り値(2個返す場合) t, ok := i.(T)

1個目:

  • 成功:interface型の変数が実際にチェックした型を持っている場合、チェックした型のunderlying typeの値として返す

  • 失敗:interface型の変数が実際にチェックした型を持っていない場合、チェックした型のZero valueを返す

2個目:

  • 成功 : true

  • 失敗: false

戻り値(1個返す場合) t := i.(T)

1個目:

  • 成功:interface型の変数が実際にチェックした型を持っている場合、チェックした型の変数として返す( interfaceT

  • 失敗:panic

ポイント(ではないかもしれないけど)

  1. assertionが成功した場合は、underlying typeの値を取得できる → 各typeに応じた処理が書ける
  2. 戻り値が1個の場合は、失敗すると panic が起きる

CLI作成で使うパッケージ② spf13/viper

Topic

configuration周りは spf13/viper を利用する

Summary

viperは以下をサポートしている

  • setting defaults
  • reading from JSON, TOML, YAML, HCL, envfile and Java - properties config files
  • live watching and re-reading of config files (optional)
  • reading from environment variables
  • reading from remote config systems (etcd or Consul), and - watching changes
  • reading from command line flags
  • reading from buffer
  • setting explicit values

Pro Tip: Keep Viper Isolated → Config Packageを用意する

https://carolynvanslyck.com/talk/go/cli/#/sting-of-the-viper

→ the configuration was loaded once

→ App structをリファクタ

https://carolynvanslyck.com/talk/go/cli/#/app-with-config-pkg

  • App take in a config load it up
  • save that struct
  • work with it

How's day been?

Good 😉

Graph representation 隣接リストでのグラフ表現

Topic

グラフ表現の復習

※自分用のまとめノートなので、誤った認識で書かれてる可能性あり

Graph representation

今回は基本の隣接リストでのグラフ表現の実装の復習。

ちなみに、グラフ表現では大きく4種類の方法があるらしい。*1

f:id:mizushou:20201228042419p:plain

やりたいこと

こんなグラフや、あんなグラフをコード上で表現して、BFS,DFSなどで走査(検索)したい

f:id:mizushou:20201228042057p:plainf:id:mizushou:20201228042248p:plain

Adjacency lists

  • array Adj of $|V|$
  • each element in the array is a pointer to a linked list
  • for each vertex $v \in V$, Adj[v] stores $v$'s neighbors
  • ${ v \in V | (u,v) \in E }$ directed
  • ${ v \in V | {u,v} \in E }$ undirected

Adjacency listの例

  • $|V| = 3$
  • $|E| = 4$
  • Space complexity : $\Theta(|V|+|E|)$
    • Undirectedの時はEdgeが2倍だが $\Theta(|V|+|E|)$
f:id:mizushou:20201228042454j:plainf:id:mizushou:20201228042504p:plain

Adjacency listの実装

  • 一番単純なのはArray (ArrayList)で実装する方法。あとは Dictionary (HashTable)など
  • 各要素の入れ物(隣接するノードをいれる)を何にするかも実装者による
  • 今回は以下のように実装した

    • Adjacency list自体はDictionay (HashMap)
    • 各要素はSet (HashSet)
    • メリットは、同じ辺を追加してしまった時に重複してAdjacency listに登録されることがない

      java private HashMap<Integer, HashSet<Integer>> adjacencyList;

  • Adjacency listのインターフェース

    • インターフェースを用意してみた
    • 実際は配列orハッシュテーブルに↑の図のように頂点を追加できればいいだけなので、object oriented likeにやる必要はない
    • 辺の追加( addDirectedEdge addUnDirectedEdge)、指定した頂点に隣接する頂点を返す( neighbors )メソッドはBFS, DFSを実行する上で必要
    • 最後にデバッグ用に printGraphも定義した
public interface Graph {

    public void addDirectedEdge(int i, int j);
    public void addUnDirectedEdge(int i, int j);
    public HashSet<Integer> neighbors(int i);
    public void removeEdge(int i, int j);
    public boolean hasEdge(int i, int j);
    public List<Integer> inEdge(int i);
    
    public void printGraph();
}
public static void main(String[] args) {

        // #1 Directed
        // Create the graph
        int V = 3;
        GraphAsAdjList graph = new GraphAsAdjList(V);

        graph.addDirectedEdge(0,2); // a -> c
        graph.addDirectedEdge(1,0); // b -> a
        graph.addDirectedEdge(1,2); // b -> c
        graph.addDirectedEdge(2,1); // c -> b

        graph.printGraph();
}
vertex 0|-> 2
vertex 1|-> 0-> 2
vertex 2|-> 1

参考にしたもの