20190203のNode.jsに関する記事は11件です。

Docker で Node.js 開発環境を簡単に用意する

概要

Docker を使って、ローカルを汚すことなく Node.js の開発環境を作る方法です。数行の docker-compose.yml を書いて、あとは随時コンテナを起動してコマンドを実行するだけです。

環境

  • macOS Mojave v10.14.2
  • Docker Desktop Community v2.0.0.2

手順

  1. Docker Desktop をインストールします。
  2. 開発用ディレクトリ(Git リポジトリ等)を用意します。
  3. docker-compose.yml を書きます。

手順 1、2 については特に説明は不要だと思うので省略します。

docker-compose.yml を書く

以下を書きます。

docker-compose.yml
version: '3'
services:
  app:
    image: node:11.8.0
    ports:
      - $PORT:$PORT
    volumes:
      - ./:/src
    working_dir: /src
.env
PORT=8080
  • app — サービス名。好きな名前を付けます。
  • image — Docker の公式イメージを使います。バージョンは開発する目的に合わせて指定してください。
  • ports — Express を使って Web サーバを立てる場合など、ホスト・ゲスト間で通信が必要な場合はポートを指定します。今回は環境変数で指定できるようにしました。
  • volumes — ホスト側のディレクトリをゲストにマウントします。
  • working_dir — コンテナ起動後のカレントディレクトリを指定します。npm install を実行する package.json があるディレクトリを指定するとよいでしょう。

以上で準備完了です!

必要な場合はビルドを

パッケージマネージャに Yarn を使用するなど、Node.js のイメージに何かをインストールする必要がある場合は、Dockerfile を書いてビルドしておきます。

実行

あとは docker-compose run --rm <サービス名> <コマンド> で Node.js を使った何かを随時実行するだけです(以下、サービス名を app とします)。--rm オプションは、コマンド終了後にコンテナを自動的に削除してくれます。

npm で任意のライブラリをインストールする

docker-compose run --rm app npm install <パッケージ名>

package.json の依存ライブラリをインストールする

開発環境を他の人に提供するときなど。

docker-compose run --rm app npm install

package.json で定義したスクリプトを実行する

Express で Web サーバを起動するなど、package.json で定義したスクリプトを実行する場合。

package.json
{
  "scripts": {
    "start": "node --experimental-modules index.mjs"
  }
}

docker-compose.yml の ports で指定したポートを通すには --service-ports オプションを付けます。

docker-compose run --rm --service-ports app npm start

よく使うコマンドはシェルスクリプトで

毎回 docker-compose run --rm app ... と打つのは面倒なので、よく使うコマンドはシェルスクリプトにしておくとよいです。

例えば、開発環境を構築するためのコマンドを一つのシェルスクリプトに書いておくことで、他の人が開発環境を簡単に準備できるようになります。

prepare.sh
#!/bin/bash

echo 'PORT=8080' >> .env && \
docker-compose run --rm app npm install

まとめ

  • docker-compose.yml で Node.js のイメージとボリューム、ワーキングディレクトリ等を定義します。
  • docker-compose run --rm <サービス名> <コマンド> で随時コンテナ作成、コマンド実行、コンテナ削除を行います。

それでは、快適な Docker ライフを!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Terser】Nuxt.jsで突然ビルドエラーが発生したときの対応法

はじめに

現在、Nuxt.jsとNetlifyを使用して個人で開発を行なっています。
その際にNetlifyでビルドを行なったときに突然エラーが発生するようになりました。
本記事では、そのときの対処法について、備忘録として記したいと思います。

エラー内容

ビルドを行なったときに、以下のようなエラーが発生するようになりました。

5:39:27 PM: ERROR in 6f8075b97658f08b5126.js from Terser
5:39:27 PM: TypeError: Cannot read property 'minify' of undefined
5:39:27 PM:     at minify (/opt/build/repo/node_modules/terser-webpack-plugin/dist/minify.js:175:23)
5:39:27 PM:     at module.exports (/opt/build/repo/node_modules/terser-webpack-plugin/dist/worker.js:13:40)
5:39:27 PM:     at handle (/opt/build/repo/node_modules/worker-farm/lib/child/index.js:44:8)
5:39:27 PM:     at process.<anonymous> (/opt/build/repo/node_modules/worker-farm/lib/child/index.js:51:3)
5:39:27 PM:     at emitTwo (events.js:126:13)
5:39:27 PM:     at process.emit (events.js:214:7)
5:39:27 PM:     at emit (internal/child_process.js:762:12)
5:39:27 PM:     at _combinedTickCallback (internal/process/next_tick.js:142:11)
5:39:27 PM:     at process._tickCallback (internal/process/next_tick.js:181:9)

対処法

package.jsonに下記の記述を追記するとビルドが正常に行われるようになりました。

package.json
"resolutions": {
  "terser": "3.14.1"
}

4.参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

サブライムテキストでJavascript の予測変換機能を追加してみた①

WEBサイト制作で使っているsublimeText(サブライムテキスト)で、Javascriptの予測変換機能を追加してみた。

これで、querySelectorといった長ったらしいメソッドも楽に入力できるに違いない。

でも、どうやらそのためには、「jshint」というプラグインがあるらしいが、前提としてNode.jsをインストールしておく必要があるとのこと。
Node.jsというのは、「サーバーサイドで動くJavascript」のこと。詳細を調べると、複雑すぎて(⁰▿⁰)だったので、とりあえずは左のような浅い理解で今はOKとさせてください。
参照サイト
後々、ドットインストール等で勉強します。
以下に、Node.jsインストール・jshint追加までの手順を記します。

参考にした記事
- https://qiita.com/akakuro43/items/600e7e4695588ab2958d)
- https://qiita.com/omega999/items/6f65217b81ad3fffe7e6
- JavaScriptのためのSublime Textプラグイン

① homebrewのインストール

homebrewというのは、Mac用のパッケージマネージャ。→公式サイト
パッケージマネージャーというのは、OSという一つの環境で各種のソフトウェアの管理、ソフトウェア同士やライブラリとの依存関係を管理するシステム。(Wikipediaから引用)
⬇︎
Macターミナルを起動して、以下のコマンドを実行。
※homebrew公式サイトの「インストール」項目を参照

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールできたか確認するために、「brew doctor」と打ち込んだら、変な表示がされた。
「brew doctor」というのは、インストールされたhomebrewの問題をチェックしてくれるコマンド。

Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: "config" scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and what additional flags to use when
compiling and linking.

Having additional scripts in your path can confuse software installed via
Homebrew if the config script overrides a system or Homebrew provided
script of the same name. We found the following "config" scripts:
  /anaconda3/bin/icu-config
  /anaconda3/bin/freetype-config
  /anaconda3/bin/xslt-config
  /anaconda3/bin/libpng16-config
  /anaconda3/bin/python3.7-config
  /anaconda3/bin/libpng-config
  /anaconda3/bin/xml2-config
  /anaconda3/bin/python3.7m-config
  /anaconda3/bin/python3-config
  /anaconda3/bin/curl-config
  /anaconda3/bin/ncursesw6-config
  /anaconda3/bin/pcre-config

Warning: Broken symlinks were found. Remove them with `brew cleanup`:
  /usr/local/bin/mono-boehm
  /usr/local/bin/prj2make

Warningということは「警告」ってこと?
一つ目の警告から、調べてみた。
①. 「Warning: "config" scripts exist outside your system or Homebrew directories.」
(警告: "config"スクリプトはあなたのシステムまたは自作ディレクトリの外にあります。)
解決方法はここを参考にしたけどうまくできませんでした。そもそもbashなどといったシェルの知識を持ち合わせていないから、参考記事のコードをコピペしても何をしているのかさっぱり分かりません。
とりあえず致命的な警告ではないので、ここは飛ばします。
シェルスクリプトは、後々ドットインストール等で勉強します。
https://dotinstall.com/lessons/basic_shellscript_v2

二つ目の警告は、
②. 「Warning: Broken symlinks were found. Remove them with brew cleanup
(壊れたシンボリックリンクが見つかりました。 brew cleanupでそれらを削除してください。)
これは、メッセージ通りに、

MyMac:~ takawaki$ brew cleanup

を実行した後は、警告が出なくなった。

シンボリックリンク
OSのファイルシステムの機能の一つで、特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組み。UNIX系OSでよく用いられるもので、Windowsでも利用することができる。
ショートカットと同じじゃないの?と思ったが厳密には違うみたいです。→参考サイト

②nodebrewのインストール

nodebrewとは、node.jsを自分のマシン内でversion管理するためのツール。
プロジェクトごとにnode.jsのversionが違っていたりすると、不具合が起こるのでそれを解決してくれる。

参考記事

以下のコマンドを実行して、確認のためバージョン確認。

brew install nodebrew
nodebrew -v

⬇︎
実行結果

nodebrew 1.0.1

Usage:
    nodebrew help                         Show this message
    nodebrew install <version>            Download and install <version> (from binary)
    nodebrew compile <version>            Download and install <version> (from source)
    nodebrew install-binary <version>     Alias of `install` (For backword compatibility)
    nodebrew uninstall <version>          Uninstall <version>
    nodebrew use <version>                Use <version>
    nodebrew list                         List installed versions
    nodebrew ls                           Alias for `list`
    nodebrew ls-remote                    List remote versions
    nodebrew ls-all                       List remote and installed versions
    nodebrew alias <key> <value>          Set alias
    nodebrew unalias <key>                Remove alias
    nodebrew clean <version> | all        Remove source file
    nodebrew selfupdate                   Update nodebrew
    nodebrew migrate-package <version>    Install global NPM packages contained in <version> to current version
    nodebrew exec <version> -- <command>  Execute <command> using specified <version>

Example:
    # install
    nodebrew install v8.9.4

    # use a specific version number
    nodebrew use v8.9.4

③Node.jsのインストール

以下のコマンドを実行

nodebrew innstall-binary latest

そしたら
以下のエラーが返ってきた

MyMac:~ takawaki$ nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz
Warning: Failed to create the file                                             
Warning: /Users/takafumi/.nodebrew/src/v11.9.0/node-v11.9.0-darwin-x64.tar.gz: 
Warning: No such file or directory
                                                                            0.0%
curl: (23) Failed writing body (0 != 846)
download failed: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz

解決策を調べた。
Node.jsのインストールに失敗する時の解決策(No such file or directory)
No such file or directoryは、「こんなファイルを知りません」というメッセージ。
だから以下のコマンドで非表示ディレクトリを作成

mkdir -p ~/.nodebrew/src

mkidirはディレクトリを作成するコマンド
-pはparentオプションで、エラーを表示せず記述したディレクトリが存在しなければ作成することができる。
ディレクトリ名の最初に、「.」をつけるのは非表示ディレクトリにするため。
作成したら、nodebrew innstall-binary latestを再実行。

MyMac:~ takawaki$ nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz
######################################################################### 100.0%
Installed successfully

インストールが成功した!念のため確認。
「nodebrew list」は、インストールされているバージョンを確認できる。
以下のコマンドでは、version11.9.0を使っていることが分かる。
```
MyMac:~ takawaki$ nodebrew list
v11.9.0

current: v11.9.0
```

④実行パスを通す

以下のコマンドでnodeコマンドへパスをbashrcへ保存。

$ echo 'export PATH=$PATH:/Users/takafumi/.nodebrew/current/bin' >> ~/.bashrc

だが、インストール確認したら次のメッセージが出た

node -v
-bash: node: command not found

なので、参考記事通りに「.bash_profile」に以下を記述
参考記事①

そして、再度確認したら、node.jsが使えるようになった!

MyMac:~ takawaki$ node -v
v11.9.0

⑤npmを使えるか確認

npmは、Node.jsのパッケージ管理システム。

MyMac:~ takawaki$ npm -v
6.5.0

インストールされていることを確認。

今回、なんどもパスを通すためにファイルをいじったけど、そもそもパスを通すということはどういうことなのかも調べた。
→参考記事:PATHを通す方法

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

サブライムテキストでJavascriptの予測変換機能を追加してみた①

WEBサイト制作で使っているsublimeText(サブライムテキスト)で、Javascriptの予測変換機能を追加してみた。

これで、querySelectorといった長ったらしいメソッドも楽に入力できるに違いない。

でも、どうやらそのためには、「jshint」というプラグインがあるらしいが、前提としてNode.jsをインストールしておく必要があるとのこと。
Node.jsというのは、「サーバーサイドで動くJavascript」のこと。詳細を調べると、複雑すぎて(⁰▿⁰)だったので、とりあえずは左のような浅い理解で今はOKとさせてください。
参照サイト
後々、ドットインストール等で勉強します。
以下に、Node.jsインストール・jshint追加までの手順を記します。

参考にした記事
- https://qiita.com/akakuro43/items/600e7e4695588ab2958d)
- https://qiita.com/omega999/items/6f65217b81ad3fffe7e6
- JavaScriptのためのSublime Textプラグイン

①homebrewのインストール

homebrewというのは、Mac用のパッケージマネージャ。→公式サイト
パッケージマネージャーというのは、OSという一つの環境で各種のソフトウェアの管理、ソフトウェア同士やライブラリとの依存関係を管理するシステム。(Wikipediaから引用)
⬇︎
Macターミナルを起動して、以下のコマンドを実行。
※homebrew公式サイトの「インストール」項目を参照

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールできたか確認するために、「brew doctor」と打ち込んだら、変な表示がされた。
「brew doctor」というのは、インストールされたhomebrewの問題をチェックしてくれるコマンド。

Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: "config" scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and what additional flags to use when
compiling and linking.

Having additional scripts in your path can confuse software installed via
Homebrew if the config script overrides a system or Homebrew provided
script of the same name. We found the following "config" scripts:
  /anaconda3/bin/icu-config
  /anaconda3/bin/freetype-config
  /anaconda3/bin/xslt-config
  /anaconda3/bin/libpng16-config
  /anaconda3/bin/python3.7-config
  /anaconda3/bin/libpng-config
  /anaconda3/bin/xml2-config
  /anaconda3/bin/python3.7m-config
  /anaconda3/bin/python3-config
  /anaconda3/bin/curl-config
  /anaconda3/bin/ncursesw6-config
  /anaconda3/bin/pcre-config

Warning: Broken symlinks were found. Remove them with `brew cleanup`:
  /usr/local/bin/mono-boehm
  /usr/local/bin/prj2make

Warningということは「警告」ってこと?
一つ目の警告から、調べてみた。
①. 「Warning: "config" scripts exist outside your system or Homebrew directories.」
(警告: "config"スクリプトはあなたのシステムまたは自作ディレクトリの外にあります。)
解決方法はここを参考にしたけどうまくできませんでした。そもそもbashなどといったシェルの知識を持ち合わせていないから、参考記事のコードをコピペしても何をしているのかさっぱり分かりません。
とりあえず致命的な警告ではないので、ここは飛ばします。
シェルスクリプトは、後々ドットインストール等で勉強します。
https://dotinstall.com/lessons/basic_shellscript_v2

二つ目の警告は、
②. 「Warning: Broken symlinks were found. Remove them with brew cleanup
(壊れたシンボリックリンクが見つかりました。 brew cleanupでそれらを削除してください。)
これは、メッセージ通りに、

MyMac:~ takawaki$ brew cleanup

を実行した後は、警告が出なくなった。

シンボリックリンク
OSのファイルシステムの機能の一つで、特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組み。UNIX系OSでよく用いられるもので、Windowsでも利用することができる。
ショートカットと同じじゃないの?と思ったが厳密には違うみたいです。→参考サイト

②nodebrewのインストール

nodebrewとは、node.jsを自分のマシン内でversion管理するためのツール。
プロジェクトごとにnode.jsのversionが違っていたりすると、不具合が起こるのでそれを解決してくれる。

参考記事

以下のコマンドを実行して、確認のためバージョン確認。

brew install nodebrew
nodebrew -v

⬇︎
実行結果

nodebrew 1.0.1

Usage:
    nodebrew help                         Show this message
    nodebrew install <version>            Download and install <version> (from binary)
    nodebrew compile <version>            Download and install <version> (from source)
    nodebrew install-binary <version>     Alias of `install` (For backword compatibility)
    nodebrew uninstall <version>          Uninstall <version>
    nodebrew use <version>                Use <version>
    nodebrew list                         List installed versions
    nodebrew ls                           Alias for `list`
    nodebrew ls-remote                    List remote versions
    nodebrew ls-all                       List remote and installed versions
    nodebrew alias <key> <value>          Set alias
    nodebrew unalias <key>                Remove alias
    nodebrew clean <version> | all        Remove source file
    nodebrew selfupdate                   Update nodebrew
    nodebrew migrate-package <version>    Install global NPM packages contained in <version> to current version
    nodebrew exec <version> -- <command>  Execute <command> using specified <version>

Example:
    # install
    nodebrew install v8.9.4

    # use a specific version number
    nodebrew use v8.9.4

③Node.jsのインストール

以下のコマンドを実行

nodebrew innstall-binary latest

そしたら
以下のエラーが返ってきた

MyMac:~ takawaki$ nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz
Warning: Failed to create the file                                             
Warning: /Users/takafumi/.nodebrew/src/v11.9.0/node-v11.9.0-darwin-x64.tar.gz: 
Warning: No such file or directory
                                                                            0.0%
curl: (23) Failed writing body (0 != 846)
download failed: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz

解決策を調べた。
Node.jsのインストールに失敗する時の解決策(No such file or directory)
No such file or directoryは、「こんなファイルを知りません」というメッセージ。
だから以下のコマンドで非表示ディレクトリを作成

mkdir -p ~/.nodebrew/src

mkidirはディレクトリを作成するコマンド
-pはparentオプションで、エラーを表示せず記述したディレクトリが存在しなければ作成することができる。
ディレクトリ名の最初に、「.」をつけるのは非表示ディレクトリにするため。
作成したら、nodebrew install-binary latestを再実行。

MyMac:~ takawaki$ nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v11.9.0/node-v11.9.0-darwin-x64.tar.gz
######################################################################### 100.0%
Installed successfully

インストールが成功した!念のため確認。
「nodebrew list」は、インストールされているバージョンを確認できる。
以下のコマンドでは、version11.9.0を使っていることが分かる。

MyMac:~ takawaki$ nodebrew list
v11.9.0

current: v11.9.0

④実行パスを通す

以下のコマンドでnodeコマンドへパスをbashrcへ保存。

$ echo 'export PATH=$PATH:/Users/takafumi/.nodebrew/current/bin' >> ~/.bashrc

だが、インストール確認したら次のメッセージが出た

node -v
-bash: node: command not found

なので、参考記事通りに「.bash_profile」に以下を記述
参考記事①

そして、再度確認したら、node.jsが使えるようになった!

MyMac:~ takawaki$ node -v
v11.9.0

⑤npmを使えるか確認

npmは、Node.jsのパッケージ管理システム。

MyMac:~ takawaki$ npm -v
6.5.0

インストールされていることを確認。

今回、なんどもパスを通すためにファイルをいじったけど、そもそもパスを通すということはどういうことなのかも調べた。
→参考記事:PATHを通す方法

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

S3へのアウトプット

こんにちは。AWS lambdaのAPIでS3のアウトプットについて簡単ながら書いていきます。

内容は言語はNode.jsで書いてますが、どの言語でもエッセンスは関係ない基礎的なところかなと思います。
参考文献:
https://www.amazon.co.jp/AWS%E3%81%AB%E3%82%88%E3%82%8B%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%83%AC%E3%82%B9%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3-Peter-Sbarski/dp/4798155160/ref=sr_1_1?ie=UTF8&qid=1549178089&sr=8-1&keywords=%E3%82%B5%E3%83%BC%E3%83%90%E3%83%AC%E3%82%B9%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3

ではAWS LambdaのAPIで「バケット1」から、バケット内のファイルをアウトプットしましょう!!

        Outputs: [    
                Key: "任意のファイル名"+ '.mp4等、ファイルの種類'
        ]

でlanbdaの中でアウトプットを作ることが出来ます。

ファイルだけじゃなくてフォルダを作りたい!という方は
ファイル名の前に

        Outputs: [    
                Key: "任意のフォルダ名" + "/" + "任意のファイル名" + '.mp4等、ファイルの種類'
        ]

のように "/" を付けるとフォルダが出来上がって、ファイルが格納されている状態になっちゃいます。

複数のファイルをアウトプットに入れたい場合は

        Outputs: [    
                {Key: "任意のフォルダ名" + "/" + "任意のファイル名" + '.mp4等、ファイルの種類'},
                {.............},
                {.............}・・・
        ]

と続けていけばいいです。

ここで、フォルダ名を同一のものにすると、同一フォルダに複数ファイルが格納された状態になります。

以上です。
読んでくださってありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CLIでMapを確認する方法

CLIでlocation情報であるlat, locを指定してMap上で表示するツールを探していたのですが、なかなか見つからなかったので、なにか良いものがあったら教えてください。

一応、見つかったものを紹介します。できれば、(1)lat,locでqueryできること、(2)google mapで拡大、縮小できることが条件なんですけど、一方しか見つかりませんでした。

blessed-contrib:map

# とりあえずサーバー情報を引き出してみる
$ whois example.com
$ nslookup exmaple.com
8.8.8.8
# 仮にipが8.8.8.8だったとする, サーバーのおおよその位置をblessed-contribを使って世界地図上で表示してみる
# https://github.com/yaronn/blessed-contrib
$ git clone https://github.com/yaronn/blessed-contrib.git
$ cd blessed-contrib
$ vim examples/map-query-location.js
blessed-contrib/examples/map-query-location.js
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , map = contrib.map({label: 'World Map'})
  , loc = process.argv[2]
  , rLoc = loc.split(",")

screen.append(map)
map.addMarker({"lat" : rLoc[0], "lon" : rLoc[1], color: "red", char: "X" })

screen.render()

nodeのblessed-contribに触発され、golangやrustで書かれたものもあるみたいです。これらを使ってcli toolを書くと便利そう。

https://github.com/gizak/termui

https://github.com/fdehau/tui-rs

mapscii

# https://github.com/rastapasta/mapscii
$ sudo npm install -g mapscii
$ mapscii

...こちらはqueryできない

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでお手軽にランダム文字列の生成

お手軽さを重視しているため、作り方に偏りがある事が分かっている物もある。

以下の環境で確認

  • Node: v10.15.0
  • ブラウザ: Chrome 71.0.3578.98, Firefox 64.0.2

Edgeやモバイルの動作確認はしてない。

Node/ブラウザ共通

短いコードで

[a-v][0-9]の32文字で12桁以下なら、これでそれっぽいのが作れる。StackOverflowで知った

しかし、末端の0がくると省略されるため、任意の桁数が得られるとは限らない。以下のコードでも100万回ぐらい生成を繰り返すと6桁のものがでてきたりする。

Math.random().toString(32).substring(2) // 'a6dpgjqlq8g' 等

任意の桁数・任意の文字で

var S="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var N=16
Array.from(Array(N)).map(()=>S[Math.floor(Math.random()*S.length)]).join('')

一番最初に考えたやり方がこれだった。

なお、Array(N)だけでは長さNの配列になっているが要素が無い状態のため、mapが機能しないらしい。
そのため、Array.from(Array(N))としてやることで、undefinedな要素が入りmapが機能するようになる。(ES6以降なら、Array.fromの代わりに[...Array(N)]が使える。以降はES6/ES5ごちゃまぜになっている。)

ブラウザ

よりセキュアな乱数生成器で

「Math.randomはセキュアではないのでは?」という難癖をつける場合、crypto.getRandomValuesがあるのでこちらを使う。結構古いブラウザもサポートしてる模様。IE11もmsCryptoから使える。

以下の方法は除算を使うので特定の文字に偏りが起きる。なのでセキュア志向なら使ったらダメ。(以下の例だと[a-h]が出やすい)

var S="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var N=16
Array.from(crypto.getRandomValues(new Uint8Array(N))).map((n)=>S[n%S.length]).join('')

なお、Uint8ArrayからUint32Arrayにすると偏りは少しはマシになる。後述。

これよりも任意の文字を偏りなく出す方法を他のAPIで出来ないか考えたけど、すぐに思い浮かばなかったので諦めてます。

Base64で

文字を用意するのが面倒な場合、String.fromCharCodeで変換してからbtoaでBase64変換を使う手がある。

複雑な記号は使えないが、除算を使わない分こっちのほうが偏りも少ない気がする。(未調査)

var N=16
btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(N)))).substring(0,N) 

Nodeのみ

よりセキュアな乱数生成器で

Nodeにはブラウザとは異なるAPIを持つcryptoモジュールがある。

ブラウザのcrypto.getRandomValuesと同じ動作をするcrypto.randomFillSyncがあるのでこれで。

以下の方法も同じように除算を使ってるので偏ります。

const crypto = require('crypto')
const S="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const N=16
Array.from(crypto.randomFillSync(new Uint8Array(N))).map((n)=>S[n%S.length]).join('')

Base64で

Base64も同じ要領で...と思ったが、btoaがないので、ブラウザのようには行えない。

代わりにNodeにはcrypto.randomBytesがある。これはN個のランダムなバイト列を作り、Node固有のBufferという型で返す。(crypto.randomFillSync(new Uint8Array(N))に似ているが、戻り値の型が違う。)

そして、このBufferがBase64変換に対応している。なので、もう少し短く書ける。

const crypto = retuire('crypto')
const N = 16
crypto.randomBytes(N).toString('base64').substring(0, N)

Nodeはこれが一番スマートな気がする。

おまけ:剰余計算による偏り

質の良い乱数生成期を使ったとしても、剰余を求めるやり方を行ってしまうと、偏りが起きる場合がある。

const S="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // 62文字
let p=Array(S.length).fill(0)

// 100個づつ乱数を取り出し集計する処理を6200回繰り返す(620000回行う)

for(let i=0;i<100*S.length; ++i){
  const arr = crypto.randomFillSync(new Uint8Array(100))
  for(let j=0; j<arr.length; ++j){
    p[arr[j]%S.length]++;
  }
}
p // => 均等にばらければ全部が10000前後になるはずだが、あきらかに0-7番目の要素のカウントが大きいことが分かる。

これは、0~255(256個)がランダムで得られたとしても、剰余計算によって0~61(62個)のいずれかになる。
すると、0~61,62~123, 124~185,186~247の間は均等に出現するが、残りの248~255は0~7しか出現しえないため、この分が他と比べて多く出る。これで偏りが起きる。
逆に256を割り切れる数(2,4,8...64,128)で割れば計算による偏りは起きない。もし偏る場合は元の乱数の問題。

また、ランダムで得られる範囲0-255と狭いせいというのもあるので、この範囲を十分に大きくすると剰余計算による偏りは減らすことができる。
上記のコードなら、Uint8Array => Uint32Array にしてみると、偏りが目立たなくなることがわかる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JS】setTimeoutを用いた、非同期処理入門

概要

setTimeoutを用いて、非同期処理の処理順をまとめました。
コールバック -> Promise -> async/await の順に説明する。

setTimeout

基本構文

setTimeout('コールバック関数', 'タイムアウト時間')

1秒後にhogeを出力する。

function callback(){
    console.log('hoge')
}

setTimeout(callback, 1000)
出力結果
hoge

alt

無名関数を用いて書く。

setTimeout(function(){ console.log('hoge') }, 1000)

アロー演算子を用いて書く。

setTimeout(() => { console.log('hoge') }, 1000)

アロー演算子を用いて書く。(中括弧を省略)

setTimeout(() => console.log('hoge'), 1000)

処理順

非同期処理の処理順を確認する。

console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(3)
出力結果
1
3
2

alt

timeout時間 0秒 でも、処理順は変わらない。

console.log(1)
setTimeout(() => console.log(2), 0)
console.log(3)
出力結果
1
3
2

alt

コールバック地獄

非同期処理が複数重なると、コールバック地獄に陥る。

setTimeout(() => {
    console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 1000)
    }, 1000)
}, 1000)
出力結果
1
2
3

alt

コールバック地獄の回避方法

Promise化すると、thenを用いたメソッドチェーンで処理を繋げられる。

new Promise(function(resolve) {
    resolve('Hello')
}).then(function(value) {
    console.log(value)    // Hello
    return 'World'
}).then(function(value) {
    console.log(value)    // World
})
出力結果
Hello
World

resolve、returnの値が、コールバック関数の引数になる。
アロー演算子を用いて書き換えてみる。

new Promise(resolve => resolve('Hello'))
.then(value => {
    console.log(value)    // Hello
    return 'World'
}).then(value => {
    console.log(value)    // World
})
出力結果
Hello
World

コールバック地獄を、Promiseで書き直してみる。

function sleep(ms) {
    return new Promise(function(resolve) { 
        setTimeout(function() { 
            resolve() 
        }, ms)
    })
} 

sleep(1000)
.then(function() {
    console.log(1)
    return sleep(1000)
}).then(function() {
    console.log(2)
    return sleep(1000)
}).then(function() {
    console.log(3)
})
出力結果
1
2
3

Promiseとアロー演算子を用いて書き換えてみる。

const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms))

sleep(1000)
.then(() => {
    console.log(1)
    return sleep(1000)
}).then(() => {
    console.log(2)
    return sleep(1000)
}).then(() => {
    console.log(3)
})
出力結果
1
2
3

alt

async関数内で、Promise関数にawaitを用いると、同期的に処理できる。

function sleep(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    })
}

async function asyncFunc() {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()
出力結果
1
2
3

async/await とアロー演算子を用いた場合

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const asyncFunc = async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()
出力結果
1
2
3

更に、即時関数を用いて書くと、簡潔に書ける。

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

!(async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
})()
出力結果
1
2
3

alt

まとめ

非同期処理の処理順をまとめました。
async/await を用いることで、とても簡潔に書けます。
間違い・指摘等があればコメントお願いします。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

setTimeoutを用いた、非同期処理入門

概要

setTimeoutを用いて、非同期処理の処理順をまとめました。
コールバック -> Promise -> async/await の順に説明する。

setTimeout

基本構文

setTimeout(コールバック関数, タイムアウト時間)

1秒後にhogeを出力する

function callback(){
    console.log('hoge')
}

setTimeout(callback, 1000)

alt

無名関数を用いて書く

setTimeout(function(){ console.log('hoge') }, 1000)

アロー演算子を用いて書く

setTimeout(() => { console.log('hoge') }, 1000)

アロー演算子を用いて書く(中括弧を省略)

setTimeout(() => console.log('hoge'), 1000)

処理順

非同期処理の処理順を確認する

console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(3)

// 1 -> 3 -> 2

alt

timeout時間 0秒 でも、処理順は変わらない

console.log(1)
setTimeout(() => console.log(2), 0)
console.log(3)

// 1 -> 3 -> 2

alt

同期的に処理したい場合

Promise化すると、thenを用いたメソッドチェーンで処理を繋げられる

const promiseTimeout = new Promise(function(resolve) {
    setTimeout(function() {
        console.log(2)
        resolve()
    }, 1000)
})

console.log(1)
promiseTimeout.then(function() { console.log(3) })

// 1 -> 2 -> 3

Promiseとアロー演算子を用いた場合

const promiseTimeout = new Promise(resolve =>
    setTimeout(() => {
        console.log(2)
        resolve()
    }, 1000)
)

console.log(1)
promiseTimeout.then(() => console.log(3))

// 1 -> 2 -> 3

alt

async関数内で、Promise関数にawaitを用いると、同期的に処理できる

function promiseTimeout() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(2)
            resolve()
        }, 1000)
    }) 
}

async function asyncFunc() {
    console.log(1)
    await promiseTimeout()
    console.log(3)
}

asyncFunc()

async/await とアロー演算子を用いた場合

const promiseTimeout = () => 
    new Promise(resolve => 
        setTimeout(() => {
            console.log(2)
            resolve()
        }, 1000)
    )

const asyncFunc = async () => {
    console.log(1)
    await promiseTimeout()
    console.log(3)
}

asyncFunc()

alt

まとめ

非同期処理の処理順をまとめました。
async/await を用いることで、とても簡潔に書けます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

setTimeoutを用いた非同期処理入門

概要

setTimeoutを用いて、非同期処理の処理順をまとめました。
コールバック -> Promise -> async/await の順に説明する。

setTimeout

基本構文

setTimeout(コールバック関数, タイムアウト時間)

1秒後にhogeを出力する

function callback(){
    console.log('hoge')
}

setTimeout(callback, 1000)

alt

無名関数を用いて書く

setTimeout(function(){ console.log('hoge') }, 1000)

アロー演算子を用いて書く

setTimeout(() => { console.log('hoge') }, 1000)

アロー演算子を用いて書く(中括弧を省略)

setTimeout(() => console.log('hoge'), 1000)

処理順

非同期処理の処理順を確認する

console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(3)

// 1 -> 3 -> 2

alt

timeout時間 0秒 でも、処理順は変わらない

console.log(1)
setTimeout(() => console.log(2), 0)
console.log(3)

// 1 -> 3 -> 2

alt

コールバック地獄

非同期処理が複数重なると、コールバック地獄に陥る

setTimeout(() => {
    console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 1000)
    }, 1000)
}, 1000)

// 1 -> 2 -> 3

alt

コールバック地獄の回避方法

Promise化すると、thenを用いたメソッドチェーンで処理を繋げられる

const promiseTimeout = new Promise(function(resolve) {
    setTimeout(function() {
        console.log(2)
        resolve()
    }, 1000)
})

console.log(1)
promiseTimeout.then(function() { console.log(3) })

// 1 -> 2 -> 3

Promiseとアロー演算子を用いた場合

const promiseTimeout = new Promise(resolve =>
    setTimeout(() => {
        console.log(2)
        resolve()
    }, 1000)
)

console.log(1)
promiseTimeout.then(() => console.log(3))

// 1 -> 2 -> 3

alt

async関数内で、Promise関数にawaitを用いると、同期的に処理できる

function promiseTimeout() {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(2)
            resolve()
        }, 1000)
    }) 
}

async function asyncFunc() {
    console.log(1)
    await promiseTimeout()
    console.log(3)
}

asyncFunc()

// 1 -> 2 -> 3

async/await とアロー演算子を用いた場合

const promiseTimeout = () => 
    new Promise(resolve => 
        setTimeout(() => {
            console.log(2)
            resolve()
        }, 1000)
    )

const asyncFunc = async () => {
    console.log(1)
    await promiseTimeout()
    console.log(3)
}

asyncFunc()

// 1 -> 2 -> 3

alt

まとめ

非同期処理の処理順をまとめました。
async/await を用いることで、とても簡潔に書けます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】setTimeoutを用いた、非同期処理入門

概要

setTimeoutを用いて、非同期処理の処理順をまとめました。
コールバック -> Promise -> async/await の順に説明する。

setTimeout

基本構文

setTimeout('コールバック関数', 'タイムアウト時間')

1秒後にhogeを出力する。

function callback(){
    console.log('hoge')
}

setTimeout(callback, 1000)

alt

無名関数を用いて書く。

setTimeout(function(){ console.log('hoge') }, 1000)

アロー演算子を用いて書く。

setTimeout(() => { console.log('hoge') }, 1000)

アロー演算子を用いて書く。(中括弧を省略)

setTimeout(() => console.log('hoge'), 1000)

処理順

非同期処理の処理順を確認する。

console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(3)

// 1 -> 3 -> 2

alt

timeout時間 0秒 でも、処理順は変わらない。

console.log(1)
setTimeout(() => console.log(2), 0)
console.log(3)

// 1 -> 3 -> 2

alt

コールバック地獄

非同期処理が複数重なると、コールバック地獄に陥る。

setTimeout(() => {
    console.log(1)
    setTimeout(() => {
        console.log(2)
        setTimeout(() => {
            console.log(3)
        }, 1000)
    }, 1000)
}, 1000)

// 1 -> 2 -> 3

alt

コールバック地獄の回避方法

Promise化すると、thenを用いたメソッドチェーンで処理を繋げられる。

new Promise(function(resolve) {
    resolve('Hello')
}).then(function(value) {
    console.log(value)    // Hello
    return 'World'
}).then(function(value) {
    console.log(value)    // World
})

// Hello
// World

resolve、returnの値が、コールバック関数の引数になる。
アロー演算子を用いて書き換えてみる。

new Promise(resolve => resolve('Hello'))
.then(value => {
    console.log(value)    // Hello
    return 'World'
}).then(value => console.log(value))    // World

// Hello
// World

コールバック地獄を、Promiseで書き直してみる。

function sleep(ms) {
    return new Promise(function(resolve) { 
        setTimeout(function() { 
            resolve() 
        }, ms)
    })
} 

sleep(1000)
.then(function() {
    console.log(1)
    return sleep(1000)
}).then(function() {
    console.log(2)
    return sleep(1000)
}).then(function() {
    console.log(3)
})

// 1 -> 2 -> 3

Promiseとアロー演算子を用いて書き換えてみる。

const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms))

sleep(1000)
.then(() => {
    console.log(1)
    return sleep(1000)
}).then(() => {
    console.log(2)
    return sleep(1000)
}).then(() => {
    console.log(3)
})

// 1 -> 2 -> 3

alt

async関数内で、Promise関数にawaitを用いると、同期的に処理できる。

function sleep(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    })
}

async function asyncFunc() {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()

// 1 -> 2 -> 3

async/await とアロー演算子を用いた場合

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

const asyncFunc = async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
}

asyncFunc()

// 1 -> 2 -> 3

更に、即時関数を用いて書くと、簡潔に書ける。

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

!(async () => {
    await sleep(1000)
    console.log(1)
    await sleep(1000)
    console.log(2)
    await sleep(1000)
    console.log(3)
})()

// 1 -> 2 -> 3

alt

まとめ

非同期処理の処理順をまとめました。
async/await を用いることで、とても簡潔に書けます。
間違い・指摘等があればコメントお願いします。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む