Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 8823 articles
Browse latest View live

Node.jsを使ってお手軽インドカレー検索Botを作ってみた(1.簡単な応答)

$
0
0

はじめに

皆さん、LINE Bot について様々な箇所で使われているので既にご存じの方も多いと思います。
ただ自分が作るとなると少し敷居が高いように感じますが、そんなことはありません!!
無料かつアイデア次第で面白いものを作成できると思います。
僕は近くのインドカレー屋を探しすぎたのがきっかけで LINE Bot に触れてみました。(なぜかGoogleが面倒)

最終的には位置情報、フリーワードでインドカレー屋を検索、お気に入り機能の実装までを目標に紹介していきます!
まずはお手軽にNode.js(Express)を使って LINE Bot を作れることを紹介していきます!

最終目標サンプル
IMG_1803.PNG

LINE Bot 作成手順

①LINE 設定

(1)チャネルを作成

Messaging APIを始めように従ってチャネルを作成していきましょう!
チャネルの名前とかは好きなものを設定してOKです。

(2)トークンを発行

本来であればトークンの有効期限は短いほうがよいですが、実装も簡単になるため今回は長期トークンを選択します。詳しくはチャネルアクセストークンについてリファレンスを見てみてください。
作成出来たらMessaging APIのチャネルシークレットチャネルアクセストークンをメモしておきましょう!

チャネルシークレット
screenshot6.png

チャネルアクセストークン
scrennshot7.png

②ホスティングサービスの設定

(1)ホスティングサービスの選定

ホスティングサービスには色々な選択肢があると思いますが、今回はお手軽さを重視するためにHerokuを使用します!
Herokuはソースコードをプッシュしたら自動でビルド・デプロイしてくれるし、GitHubと連携もできるので、ものすごくお手軽です!

(2)アカウントの作成

Herokuを利用するにはアカウントが必要です。
Herokuの公式サイトでサクッと作っちゃいましょう!(無料です)

(3)GitとHeroku CLIのインストール

HerokuでアプリをデプロイするためにGitHeroku CLIが必要なのでインストールします。

Git
Heroku CLI

(4)Herokuスタータープログラムのclone

Gitを使ってHerokuスタータープログラムをクローンしてアプリを作成します。

コマンドライン
$ git clone https://github.com/heroku/node-js-getting-started.git
$ cd node-js-getting-started

(5)Heroku上に自分のアプリを作成してプログラムをデプロイ

Herokuでアプリを作ったら自分のアプリ名が出てきます。大事なのでメモっておきましょう。下記で言うとsharp-rain-871(アプリ名はHeroku スターターガイドから引用しています)

コマンドライン
$ heroku create
Creating sharp-rain-871... done, stack is heroku-18
//自分のアプリ名!
http://sharp-rain-871.herokuapp.com/ | https://git.heroku.com/sharp-rain-871.git
Git remote heroku added

後はクローンしたソースコードをHerokuにデプロイしてNode.jsアプリ作成完了です!

コマンドライン
$ git push heroku main

デプロイが完了したので LINE Bot アプリを作成していきます。
アプリにはLINE SDKが必要なので先にnpmで入れます。

コマンドライン
$ npm install @line/bot-sdk --save

このままだと、まだ動かないのでindex.jsを LINE Bot のチュートリアルを参考にして、下記のように受けとったメッセージをオウム返しできるように書き換えましょう!
最初にメモったチャネルシークレットチャネルアクセストークンをconfigで定義してあげてください。
(Herokuの環境変数に埋め込む方がベターですが簡便化のため直書きにしています)

index.js
constline=require('@line/bot-sdk');constexpress=require('express');// 環境変数を定義// チャネルシークレットとチャネルアクセストークンを記載constconfig={channelAccessToken:"XXXXXX",channelSecret:"XXXXX",};// create LINE SDK clientconstclient=newline.Client(config);// Expressアプリconstapp=express();// Webhookの設定app.post('/callback',line.middleware(config),(req,res)=>{Promise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result)).catch((err)=>{console.error(err);res.status(500).end();});});// ★イベントハンドラー// メッセージの返答はここで定義functionhandleEvent(event){// テキストメッセージ以外は無視if(event.type!=='message'||event.message.type!=='text'){returnPromise.resolve(null);}// 受け取ったメッセージをそのまま返す変数constecho={type:"text",text:event.message.text};// 定義したメッセージをLINE SDKのメソッドを使って返信returnclient.replyMessage(event.replyToken,echo);}// listen on portconstport=process.env.PORT||3000;app.listen(port,()=>{console.log(`listening on ${port}`);});

今回は詳細を省きますが少しだけコードの解説をします。
★イベントハンドラーの部分でメッセージのレスポンスを定義しています。今回は受けとったメッセージをそのまま返答するのでtextには引数で受け取ったevent.message.textをセットしています。eventオブジェクトについてMessaging APIリファレンスに詳細が記載あるので一度見てみてください。
index.jsを書き換えたら、Herokuにデプロイしておきましょう。これでサーバー側の準備は完了です!

③チャネルの設定

(1)Webhook URLを設定

ここまできたらあと一歩です...!
LINE Developersコンソールで、Messaging APIチャネルの[Messaging API設定]タブからWebhookのURLにhttps://自分のアプリ名.herokuapp.com/callbackを設定して応答メッセージを無効にしたら完了です!
webhook-url-heroku-com.59a8da1d.png
スクリーンショット 2021-03-10 23.11.51-1.png
これでオウム返し LINE Bot の完成です!!

(2)動作確認

せっかく作成したので動きを確認してみましょう!下記サンプルのようにオウム返しをしてくれるはずです!

サンプル
IMG_1807.PNG

終わりに

いかがでしたでしょうか??思ったより簡単に作成できたかと思います...!
次回では位置情報と、ホットペッパーAPIを活用して近くのお店を表示するよう LINE Bot をアップデートしていきます。
またメッセージ応答の詳しいカスタマイズも次回以降で紹介していきますね!

参考記事・URL

https://developers.line.biz/ja/docs/messaging-api/channel-access-tokens/
https://developers.line.biz/ja/docs/messaging-api/getting-started/
https://developers.line.biz/ja/reference/messaging-api/#create-upload-audience-group-by-file
https://qiita.com/TakuTaku04/items/cb71f10669a9e9cbf71b


【Node.js】【npm】これらは何者?

$
0
0

何かと目にすることが多いが、いまいち概要がつかめていなかったNode.jsとnpm。ざっくりとですがまとめてみました。詳細は、今後学習する中で更新していきたいと思います。

(前置き)JavaScriptとは

ブラウザ上で動くために開発されたプログラミング言語。コンテンツに動きをつけたり、DOM要素をいじったりすることができる。

・クリックしたら特定の位置まで画面がスクロールされる
・ポップアップで注意事項を表示する

等々のことが実装できる。

パソコン上で動くわけではないので、PHPやRubyなどのサーバーサイドの言語と異なり、OS上のファイル等にアクセスすることはできない。

Node.jsとは

サーバサイドのJavaScript実行環境。

Node.jsではJavaScriptでOSの機能にアクセスするプログラムを組むことができる。それにより、ブラウザ上で動作していたときはできなかった、自由なファイルの読み書き等ができるようになる。

また、クライアントサイドの(ブラウザで実行する)JavaScriptの開発環境としても使用されている。

個人的に感じた使用する理由は以下の通り

・jsのバージョン変換のツールであるBabelを使用するため

jsはバージョンの更新により新しい機能が追加されている。しかし、ブラウザの使用がついてきておらず、うまく動作しないことがある。
そこで、「新バージョンのjsで記述したもの」を「旧バージョンのjsで記述したもの」に変換して使用するという方法がとられることが多い。

・jsファイルを分割・統合するwebpackを使用するため

記述量の増加に伴い、どこに何が書いてあるかが分かりづらくなってしまい、メンテナンスがしにくくなってしまう。そこで、ファイル毎に記述内容を分別し、最終的にそれらのファイルをまとめてしまい読み込む。

・Sassをコンパイルするため

npmとは

Node.jsのパッケージ管理ツール。

パッケージとは、Vue.js、React、jQuery、webpack等のフレームワークやライブラリなどのこと。
Node.jsで使いたいフレームワークやライブラリがある場合、npmを用いてターミナル上でインストールして使用する。

Node.js? Express? yarn? ナニソレ

$
0
0

はじめに

現在,Expressでポートフォリオを作成している大学4回生です.
ポートフォリオ作るにあたっていろいろ調べまくったのでまとめます.

※注意

  • 環境構築に関する記事ではありません.
  • これを読んだからといって何を得るわけではありません

Node.js?

JavaScriptで開発をしている(目指している)方で聞いたことのない方はいないと思いますが,実際Node.jsって何者なんでしょうか?
ずばりNode.jsとはサーバーサイドで開発するためのJavaScript実行環境です!!!
ん?どゆこと?って人はひとまずソーナンダーって思ってください.これを使うことで色々便利なことがあるんです.

-使う理由

ではなぜブラウザで動くただのJavaScriptではなくNode.jsを使うのでしょうか.だって書くのは同じ言語なのに
先程も説明した通りNode.jsはサーバーサイドのJavaScript実行環境なのでブラウザで動くものより色々自由度が上がるんです.例えばファイルを読んだり,書き込んだりする際ブラウザ上のコードではできません.
なぜならそんなことができてしまうと,あるページにアクセスした際に情報が盗まれてしまうからです.でもそんな制限がある中で開発なんてできるわけありませんよね? そこでそんな制限をとっぱらったものがNode.jsなんです!!
スゴイデスヨネー
ちなみにnode.jsのバージョン管理やインストールにはnvm(Node Version Manager)を使って入れます.

Express?

でもNode.jsを使って開発するゾーってなっても,ん?なにから書けばええんや?ってなりません?
そこでありがたいのがExpressというフレームワークです.
ところでフレームワークって何者なんですかね.
日本語で言うところの骨組み。。。プログラミングで使う骨組みってなんだ?
ずばり,基本的にみんなが共通して使うような機能をまとめて,コードを書き易くしてくれるものです.

yarn(ヤーン)?

※嫌って意味ではありません.(いやーんっていうボケです.はい.流してください)
yarnの前にnpmの話をしましょう.
npmとはNode Package Managerの略でNode.jsで使えるライブラリの管理やインストール、アンインストールなどをしてくれるもので、yarnはnpmの上位互換みたいなものでとりあえずyarnを使っておけば大丈夫そです.

まとめ

  • Node.jsはJavaScriptの実行環境
  • Node.jsのバージョン管理はnvm(Node Version Manager)
  • Expressはフレームワーク
  • yarnはnpmの上位互換

以上!!

node.jsのインストール

$
0
0

結論

nvmを利用しましょう。node.jsを直接インストールすることもそりゃできますが安定バージョンを簡単に取得できるnvmは最強です。ということで、nvmのインストールを解説するよ。

nvmのインストール

$curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash

node.jsの安定バージョン

$ nvm install stable --latest-npm
$ nvm alias default stable

node.jsをインストールすれば一緒にnpmもインストールされてるはずです。念の為最新バージョンにアップデートしておきましょう。

$ npm update -g npm

起動

$node

これでnode.jsをインストールできれば完了です。

パッケージのインストール

パッケージをインストールするためにはまずinitで初期化処理が必要となります。これはパッケージがどのようなものがインストールされているかなど管理すつためのものだそうです。package.jsonファイルが作成されます。間違って消しちゃわないように。

$npm init

適当に書き込みを終えてから適当にパッケージをインストールしてみましょう。

$npm install socket.io

などどうでしょうか。ともかく何かしらインストールしてみて確認してみましょう。
何をインストールしているのかを確認には以下のコマンドです。

$npm list

おすすめのパッケージ

$npm install express-generator -g
$express -e
$npm install

とすることでディレクトリ構成とnode.jsでwebサイトを作る雛形を作成することができます。最後のインストールでは、express-generatorを使う上で必要なパケージがインストールされます。

以上です。

JavaScript製のJSON用テンプレートエンジンの調査

$
0
0

JavaScriptから複雑なJSONを動的に生成するテンプレートエンジンを必要としています。
もしおすすめのライブラリをご存知でしたらコメントください。

目的としているテンプレートエンジンの仕様ですが、以下を必要としています。

  • JSONまたは文字列をテンプレートとし、JSONを入力値とする
  • 出力結果はJSON
  • テンプレート中の指定キーワードをJSONの入力値で差し替える
  • foreach/if/unless/optional などの制御構文を持つ

から既存のライブラリを調査中です。

json-templates

サンプル1:

// Context values could be objects and arrays.consttemplate=parse("{{foo:baz}}");console.log(template.parameters);// Prints [{ key: "foo", defaultValue: "baz" }]console.log(template());// Prints "baz", using the default value.console.log(template({foo:{value:'bar'}}));// Prints { value: 'bar' } , using the given value.

サンプル2:

consttemplate=parse({match:{title:"{{myTitle}}"}});console.log(template.parameters);// Prints [{ key: "myTitle" }]console.log(template({myTitle:"test"}));// Prints { match: { title: 'test' } }

読み取れる大まかな仕様ですが、

  • テンプレートは JSONまたは文字列
  • 出力結果はJSONまたは文字列
  • キーワード差し替え機能あり
  • 制御構文なし

json-templater

json-templatesの派生ライブラリ。
機能を変えずに使い勝手を変えただけ。

サンプル1:

lettemplate={"magic_key_{{magic}}":{"key":"interpolation is nice {{value}}"}}letobject=require('json-templater/object');console.log(object(template,{magic:'key',value:'value'}));// =>// {//  magic_key_key: {//    key: 'interpolation is nice value'//  }//}

@biothings-explorer/json-transformer

サンプル1:

constjson_doc={'ensemblgene':1017};// the template is a JSON object, with value as the field from json_doc to be transformed and the key as the field to be transformed toconsttemplate={'ensembl':'ensemblgene'};console.log(transform(json_doc,template));// returns {'ensembl': 1017}

サンプル2:

letjson_doc={'ensembl':{'gene':1017},'wikipathway':[{'id':'WP123','name':'aaa'},{'id':'WP1234','name':'aaaa'}]};lettemplate={'ensembl':'ensembl.gene','pathway':{'id':'wikipathway.id','name':'wikipathway.name'}};letres=transform(json_doc,template);//returns {'ensembl': 1017, 'pathway': [{'id': 'WP123', 'name': 'aaa'}, {'id': 'WP1234', 'name': 'aaaa'}]}
  • テンプレートは JSON
  • 出力結果はJSON
  • キーワード差し替え機能あり
  • 制御構文なし

json-map-transform

consttransform=require('json-map-transform');consttemplate={title:{path:'name',transform:(val)=>val.toUpperCase()},label:{path:['category','categories'],omitValues:['',undefined,'ERROR']},vendor:{path:'meta.vendor',default:'No vendor'},'meta.photos':{path:'photos',transform:(val)=>val.map(photo=>photo.photoUrl)},'meta.id':{path:'code'}}//The json objects to be transformedconstproduct1={name:'Hello world',code:'BOOK01',category:'books',price:'200',photos:[{title:'photo1',photoUrl:'http://photo1.jpg',isCover:true},{title:'photo2',photoUrl:'http://photo2.jpg'}],meta:{vendor:'Author name'}};console.log(transform(product1,template))// =>// {//   "title": "HELLO WORLD",//   "label": "books",//   "vendor": "Author name",//   "meta": {//      "photos": [//         "http://photo1.jpg",//         "http://photo2.jpg"//      ],//      "id": "BOOK01"//    }// }
  • テンプレートは JSON
  • 出力結果はJSON
  • キーワード差し替え機能あり
  • 制御構文なし
  • テンプレート中に関数を直接記述できるのはちょっと面白い

jsonpath-template

constjpt=require('jsonpath-template');vartplString="Hello there [[$.person.name]], isn't it a [[$.daytype]] day?";varjson={person:{name:"Adam"},daytype:"nice"};vartemplate=newjpt(tplString);console.log(template.tags("[[","]]").apply(json));// => Hello there Adam, isn't is a nice day?
  • テンプレートはテキスト
  • 出力結果はテキスト
  • キーワード差し替え機能あり
  • 制御構文なし
  • タグの変更機能あり

jsonapter

サンプル1

varbbj2j=require('jsonapter');varj2j=bbj2j.instance();varinput={a:{b:{c:'value_0'},c:'value_2',d:'value_1'}};varr=j2j.run(template,input);console.log(r);// => {dest_a: 'value_2', dest_b: {dest_b0: 'VALUE_0', dest_b1: 'VALUE_1'}}

サンプル2

varnameTemplate={arrayContent:[{dataKey:'familyName'},{dataKey:'givenName'}]};vartemplate={content:{name:nameTemplate,age:{value:function(input){return2015-input;},dataKey:'birthYear'}}};varr=j2j.run(template,{familyName:'DOE',givenName:'JOE',birthYear:1980});console.log(r);// => {name: ['DOE', 'JOE'], age: 35}

サンプル3

var_=require('lodash');vartemplate={content:{dest_a:{dataKey:'a'},dest_b:{dataKey:'b',existsWhen:_.partialRight(_.has,'c')}},existsWhen:'public'};varr0=j2j.run(template,{a:'value_a',b:'value_b',public:true});console.log(r0.dest_a);// => 'value_a'console.log(r0.dest_b);// => undefinedvarr1=j2j.run(template,{a:'value_a',b:'value_b',c:0,public:true});console.log(r1.dest_a);// 'value_a'console.log(r1.dest_b);// 'value_b'varr2=j2j.run(template,{a:'value_a',b:'value_b',c:0});console.log(r2);// null because public is not presentvarr3=j2j.run(template,{a:'value_a',b:'value_b'},{public:true,c:0});console.log(r3.dest_a);// => 'value_a'console.log(r3.dest_b);// => 'value_b'
  • テンプレートはJSON
  • 出力結果はJSON
  • キーワード差し替え機能あり
  • 制御構文あり
    • 書き方に癖がある
  • lodashが必要?

templatizejs

vartemplatize=require('templatizejs')varjson={fizzBuzz:'{{fizz}}{{buzz}}',}varsecondaries=[{fizz:'Fizz'},{buzz:'Buzz'}]console.log(templatize.json(json,secondaries))// => { fizzBuzz: 'FizzBuzz' }
  • テンプレートはJSON
  • 出力結果はJSON
  • キーワード差し替え機能あり
  • 制御構文なし
  • タグの変更機能あり

Node.js メインスレッドで重い処理を行う

$
0
0

モチベーション

参考に挙げたMediumの記事を読んだので、その内容を実際に試してみました。

はじめに

Node.jsの特徴としてシングルスレッドであることが挙げられます。そのため、CPU負荷の重い処理をさせると、スレッドがブロックされてパフォーマンスが低下するので、そのような処理はNode.jsには不向きとされています。どうしても重い処理をしたいときは、マルチスレッドやマルチプロセスを用いることもできます(参考)が、いずれも重大な欠点があります。

マルチスレッドの問題

Node.jsにおけるマルチスレッドでは、基本的にlibuvが提供するthreadpoolからスレッドを取得して使うことになると思います。しかし、libuvのthreadpoolは最大で128個(既定で4個)のスレッドしか供給できません。さらに、libuvが提供するスレッドは、ファイル操作の非同期処理にも使われます。例えば、ローカルファイルの読み書きを行う場合は勿論、ドメイン名をIPアドレスに変換するresolve処理でも(/etc/resolv.confなどを読み込む必要があるので)スレッドが使用されます。そのため、threadpoolのリソースが枯渇し、スレッドが空くまで処理がブロックされ、パフォーマンスの低下を招く未来が容易に想像できます。Node.jsはC10K問題に対する銀の弾丸としての役割を期待されながら、C128問題に悩まされる結果となってしまいます。

マルチプロセスの問題

別プロセスを使用するとC10K問題が再燃します。クライアント数が増えるに従い、使用されるプロセス数も増加し、いずれ上限(linuxの場合32767個)に達してしまいます。また、プロセス数が増えるとコンテキストスイッチのオーバーヘッドが無視できなくなり、全体のパフォーマンスが低下します。さらに、各プロセスがファイル操作やネットワークアクセスを行う場合、プロセス毎にファイルデスクリプタを用意する必要があるため、こちらも資源の枯渇が心配されます。

シングルスレッドで重い処理を行うには?

やはり、シングルスレッド内でも重い処理を行う必要がありそうです。その場合、その処理が他の処理を長時間妨げないことが求められます。こういう処理のことをノンブロッキング(非同期)処理と呼ぶのでした。そうです!シングルスレッドであっても、重い処理を非同期で実行できれば大きな問題は起きません。さらに、あくまでもシングルスレッドなので、C10K問題に対しても(ある程度は)有効なはずです。

処理を非同期化するためには、Node.jsがどのように非同期実行をサポートしているのか理解することが重要です。

Node.jsのスクリプト実行手順

nodeコマンドでjavascripファイルを実行すると、まずトップレベルのコードが実行されます。トップレベルコードでは、非同期処理の実行などにより、イベントループにタスクを追加していきます。トップレベルコードがファイルの最後まで実行されると、イベントループが開始され、トップレベルコード(やイベントループで実行したタスク内)で追加された待機中タスクが実行可能なものから順番に処理されていきます。そして、イベントループ内で処理すべきタスクがなくなると、プログラムが終了します。このように、タスクをとりあえずイベントループに追加し、実行可能なものから次々と実行していくアーキテクチャをReactorパターンといいます。

例えば、次のスクリプトの実行を考えてみます。

例題
setTimeout(()=>console.log('timeout'),1000)// 1秒待つ// 実行結果// timeout

このスクリプトをNode.jsは次のように実行します。

  1. トップレベルコードであるsetTimeout関数を実行
  2. () => console.log('timeout')というタスクをイベントループに追加
  3. トップレベルコードが終了したのでイベントループ開始
  4. 実行可能なタスクをポーリング(ie. 検索して見つからなければ待機を繰り返す)
  5. (約1秒経過)
  6. 実行可能なタスク() => console.log('timeout')を発見
  7. () => console.log('timeout')を実行
  8. イベントループにタスクがないのでプログラムを終了

もう少し複雑な例も考えてみます。

例題2
setTimeout(()=>{console.log('1st timeout')setTimeout(()=>console.log('2nd timeout'),1000)},1000)setTimeout(()=>console.log('3rd timeout'),1500)// 実行結果// 1st timeout// 3rd timeout// 2nd timeout

このスクリプトをNode.jsは次のように実行します。

  1. トップレベルコードであるsetTimeout関数を実行
  2. 1stタスクをイベントループに追加
  3. トップレベルコードであるsetTimeout関数を実行
  4. 3rdタスクをイベントループに追加
  5. トップレベルコードが終了したのでイベントループ開始
  6. 実行可能なタスクをポーリング(ie. 検索して見つからなければ待機を繰り返す)
  7. (約1秒経過)
  8. 実行可能なタスクを発見
  9. 1stタスクを実行
  10. 2ndタスクをイベントループに追加
  11. (さらに約0.5秒経過)
  12. 実行可能なタスクを発見
  13. 3rdタスクを実行
  14. (さらに約0.5秒経過)
  15. 実行可能なタスクを発見
  16. 2ndタスクを実行
  17. イベントループにタスクがないのでプログラムを終了

非同期実行タスクの実行順序

ここまででNode.jsにおける非同期実行の手順を概観しました。その中で中核的な役割を担っていたのがイベントループです。

image.png
(Event Loop and the Big Pictureより引用)

前項では、単に「タスクをイベントループに追加する」と言いましたが、イベントループ内でタスクが追加できる場所は次の6種類あります。どの場所にタスクが保管されるかは、そのタスクがどのように(eg. どの関数で)イベントループに追加されるかによります。

  1. timeout (setTimeout/setInterval)
  2. IO (ノンブロッキングIO)
  3. Immediate (setImmediate)
  4. IOのclose
  5. process.nextTick
  6. Promise

イベントループにおいて「待機中タスクが実行可能なものから順番に処理されていく」際の順番は、タスクの保管場所によって決まります。

タスクの6つの保管場所は二種類に分けることができ、1~4に保管されるタスクをマクロタスク、5~6に保管されるタスクをマイクロタスクと呼びます。マクロタスクは1->2->3->4の順番で実行され、マイクロタスクは5->6の順番で実行されます。また、マイクロタスクは個々のマクロタスクの合間(イベントループ開始時を含む)に実行可能なタスクがまとめて実行されます。()

例えば、次のスクリプトを実行してみます。

例題
setImmediate(()=>console.log('immediate 1'))// 3番に追加Promise.resolve().then(()=>console.log('promise'))// 6番に追加setImmediate(()=>console.log('immediate 2'))// 3番に追加process.nextTick(()=>console.log('nextTick'))// 5番に追加// 実行結果// nextTick// promise// immediate 1// immediate 2

イベントループ開始時には、3番、5番、6番にタスクが追加されており、いずれも実行可能な状態となっています。3番はマクロタスク、5番と6番はマクロタスクの保管場所でした。そのため、まずは5番と6番にあるタスクが5->6の順番でまとめて実行されます。つぎに3番のタスクが実行されます。3番のタスクの終了後、マイクロタスクが検索されますが、見つからないため、引き続き3番のタスクが実行されます。その後、マイクロタスク->マクロタスクの順に検索されますが、いずれのタスクも見つからないため、プログラムが終了します。

(*) setTimeout関数を用いても良かったのですが、setTimeout関数は独特な挙動()をするため、例ではsetImmediate関数を用いました。

重い処理の非同期化

Node.jsの非同期実行の仕組みが分かったところで、本題である処理の非同期化をどう実現するか考えます。

シングルスレッドで並行化を行うには、いわゆる時分割方式を採れば良さそうです。例えば、今から100ミリ秒は処理Aを行い、次の200ミリ秒は処理Bを、その後150ミリ秒はまた処理Aを行う・・・という具合に、一つのスレッドを時間軸で二つの処理に分割すると、二つの処理を擬似的に並行実行できます。

時分割方式の要点は、実行する処理を途中で切り替えることです。これはイベントループを使うと実現できます。先程の例で説明すると、処理Aから処理Bへの切り替えを行うには、処理Bのを行うタスクをあらかじめイベントループに追加しておき、処理Aの続きを行うタスク(これを継続と言います)をイベントループに追加して処理Aを取り敢えず終了します。すると、Node.jsは実行可能なタスクを検索し、処理Bを行うタスクを発見して実行します。そして、処理Bでも途中で同じことを行えば、また処理Aの実行を再開することができます。

次に考えるのは、処理の途中で継続をイベントループに追加する方法です。これまで紹介してきたように、イベントループにタスクを追加する方法はいくつかあり、どの方法で追加したかによって実行順序が変わるのでした。

今回の並行化の目的は、重い処理がそのほかの処理を妨げないようにすることでした。そのため、継続はイベントループにマクロタスクとして追加される必要があります。

マイクロタスクはマクロタスクの合間に"まとめて"実行されるのでした。つまり、マイクロタスク内で新たにマイクロタスクをイベントループに追加した場合、次のマクロタスクを実行する前に、新たに追加したマイクロタスクが実行されてしまいます。そのため、もし継続をマイクロタスクとして追加することにすると、重たい処理全体が終わるまでマクロタスクの実行が完全にストップしてしまいます。マクロタスクの実行が止まると、例えば、httpリクエストを受け付けることが出来なくなってしまうので、非常に困ります。(この方法でも、重たい処理を複数個並行実行することはできます)

マクロタスクとしてタスクを追加する関数として、setTimeoutsetInterval、ノンブロッキングIO、setImmediateを紹介してきました。setTimeoutsetInterval補足で説明している理由により、動作が不安定になる可能性があります。また、IO処理ではないので、ノンブロッキングIOは使えません。そのため、ここではsetImmediateを使うのが最適です。

実装

実装例として、フィボナッチ数を求めるスクリプトを並行実行させることを考えます。フィボナッチ数を求めるプログラムを愚直に再帰で書くと、計算量は2^nと非常に大きくなります。

実装例
// 通常バージョンfunctionfib(n){if(n<=1)returnnelsereturnfib(n-1)+fib(n-2)}// 並行バージョンfunctionfib_im(n,callback){setImmediate(()=>{if(n<=1)callback(n)elsefib_im(n-1,x=>fib_im(n-2,y=>callback(x+y)))})}

実際に実行して比べてみます。通常の処理がブロックされているかを確認するために、同時にsetInterval関数を実行します。

通常バージョンを実行
conststart=newDate()setInterval(()=>{constinterval=newDate()console.log(`interval: ${interval-start}`)},500)fib(40)constend=newDate()console.log(`end: ${end-start}`)// 実行結果// end: 1589// interval: 1601// interval: 2118// interval: 2628// interval: 3142// interval: 3647   

実行結果を見ると分かる通り、フィボナッチ数を求める処理が終了するまでsetIntervalで追加したタスクは実行されていません。つまり、他の処理がブロックされています。

並行バージョンを実行
conststart=newDate()setInterval(()=>{constinterval=newDate()console.log(`interval: ${interval-start}`)},500)fib_im(30,()=>{constend=newDate()console.log(`end: ${end-start}`)})// 実行結果// interval: 501// interval: 1000// interval: 1500// interval: 2000// interval: 2500// interval: 3000// interval: 3500// interval: 4000// interval: 4500// end: 4998// interval: 5013// interval: 5520 

並行バージョンでは、フィボナッチ数が求まる前でも、setIntervalで追加したタスクが実行されています。つまり、フィボナッチ数を求める処理が他の処理をブロックしていない(ie. ノンブロッキング)ことが分かります。

このように、setImmediate関数を処理の間に挟むことによって、メインスレッドで重い処理を実行したとしても、そのほかの処理をブロックすることはありません。

オーバーヘッド

しかし、setImmediate関数を入れることによって、フィボナッチ数を求める処理のパフォーマンスが大きく低下してしまいました。通常バージョンでは、40番目のフィボナッチ数を求めるのに約1.6秒かかるのに対し、並行バージョンでは、たった30番目を求めるのに約5秒もかかっています。

対策として、setImmediate関数を常に入れるのではなく、時々入れるだけにします。では、どのようなタイミングでsetImmediate関数をいれるのが良いのでしょうか。それは、setImmediate関数を入れることによるオーバーヘッドとsetImmediate関数を入れないことによるブロッキングを天秤にかけることを意味します。今回の場合は、0.5秒に1回setInterval関数で登録した処理を行いたいので、ブロッキング時間は0.1秒くらいであって欲しいです。なので、処理時間が0.1秒を超えないぎりぎりのところでsetImmediate関数を入れるのが最適です。

実装例(error)
letsince=0functionfib_im(n,callback){constgo=()=>{if(n<=1)callback(n)elsefib_im(n-1,x=>fib_im(n-2,y=>callback(x+y)))}constnow=newDate()if(since==0)since=nowif(now-since>100){setImmediate(go)}else{go()}}// 実行結果// RangeError: Maximum call stack size exceeded

一見よさげですが、実行するとMaximun call stack size exceededエラーが発生します。これは、関数の再帰呼び出しをfib_im(n-1, x => fib_im(n-2, y => callback(x+y))という形で行っているために、再帰呼び出しされた関数が全て同一のコールスタックに積まれるためです。つまり、コールスタックのサイズは最大で2^nに達してしまいます。

ちなみに、前項の並行バージョンの実装がこのエラーを出さなかったのは、setImmediate関数を挟むとコールスタックが解放されるためです。実際、今回の実装でも処理時間の閾値を0.1秒から0.01秒くらいに減らすと、setImmediate関数が呼ばれる合間に積まれるコールスタックがシステムの制限内に収まるため問題なく動作します。

処理時間でタスクの中断箇所を決めようとするとコールスタック数が枯渇してしまうので、積まれたコールスタック数でタスクの中断箇所を決めるようにしてみます。

実装例(正常)
letdepth=0functionfib_im(n,callback){constgo=()=>{if(n<=1)callback(n)elsefib_imd(n-1,x=>fib_imd(n-2,y=>callback(x+y)))}if(depth>3000){depth=0setImmediate(go)}else{depth++go()}}// 実行結果// interval: 101// interval: 200// end: 278// interval: 314// interval: 417

今回は上手く動作しました。フィボナッチ数を求めるのにかかる時間が約5秒から約0.3秒に大幅に短縮されました。

復習

fib_im関数を単独で呼び出した場合の処理時間は約0.26秒です。

単独呼び出し
conststart=newDate()fib_im(30,()=>{constend=newDate()console.log(`end: ${end-start}`)})// 実行結果// end 262

では、このfib_im関数を複数回呼び出すとどうなるか考えてみてください。

複数回呼び出し
conststart=newDate()for(leti=0;i<3;i++){fib_im(30,()=>{constend=newDate()console.log(`end: ${end-start}`)})}// 実行結果// end 743// end 754// end 755

答えは、「各処理の処理時間は3倍になり処理は全て同時に終了する」でした。

まとめ

Node.jsのイベントループをうまく活用して処理を並行化することで、メインスレッドで重い処理を行ってもブロッキングしないようにすることが出来ることが分かりました。

最後に復習で示した現象は問題と思われるかもしれませんが、これはマルチプロセスを採用しない限り解決されません。また、setImmediateはコールバック関数を引数に取るので、今回例として挙げたスクリプトでもコールバック地獄が垣間見えます。なんとか、async/awaitで書き換えられないでしょうか。この二点の問題については、また機会があれば続編として記事にしようと思います。

おわり。

補足1

Node.jsのバージョンが11.0以上の場合に限ります。それ以前は、マイクロタスクはマクロタスクの各保管場所の実行可能タスクがすべて終了した毎に実行されていました。

setImmediate(()=>{console.log('immediate 1')setImmediate(()=>console.log('immediate 2'))process.nextTick(()=>console.log('nextTick'))})// 実行結果(<11.0)// immediate 1// immediate 2// nextTick// 実行結果(>=11.0)// immediate 1// nextTick// immediate2

補足2

Node.jsで次のスクリプトを実行すると、どんな出力が得られるでしょうか。

setTimeout(()=>callback('timeout'),0)// 1番に追加setImmediate(()=>callback('immediate'))// 3番に追加

マクロタスクは1->2->3->4という順番で実行されるので、

実行結果(予想)
timeout
immediate

となると予想されますが、実際には、

実行結果(現実)
immediate
timeout

となる"場合"があります。

これは、setTimeout関数の第二引数に0を渡した(または、第二引数を省略した)としても、timeoutは0秒ではなく1ミリ秒として扱われるためです。そのため、setTimeoutが実行された時点からイベントループでタスクが検索されるまでの間に1ミリ秒未満の時間しかかからなかった場合には、上で示したような実行結果となります。

参考

GCP Cloud Build で `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory`

$
0
0

ヒープ領域が限界に近くて割り当てに失敗したらしい

Cloud Build で使われていたマシン

解決策

  • NODE_OPTIONS=--max-old-space-size=xxx
    • xxxにメガバイト単位の数字を指定。 筆者は3072と指定した
  • --max-old-space-size=xxx
    • https://nodejs.org/docs/latest-v12.x/api/cli.html#cli_node_options_options
    • ヒープの Old 領域をメガバイト単位で指定してあげる
    • 注意として,ここで指定するのは Old 領域なのでメNode.jsに割り当てられるメモリサイズ==指定サイズ とはならない
      • 指定サイズに New 領域を加算した値が実際に Node.js に割り当てられるメモリサイズになる

参考
- http://www.the-data-wrangler.com/nodejs-memory-limits/

ある時刻で関数を実行したい?それFirebase Functionsでやっちゃおうよ

$
0
0

どうもアッキーです。

ふと、日にちをまたいだ時にユーザーの決済の日にちが過ぎていないかを調べたいなと思っていたら、Firebaseで常備されているらしい。

Node.jsでcronと言うパッケージがあるらしいが、Firebaseでも実行できるらしい!

記事を見なくてもFirebaseの公式ドキュメント(関数のスケジュール設定)にも書いてあるので是非ご覧ください。

公式ドキュメントにも書いてあるのですが、この公式ドキュメントでは実行の時の時間について詳しく書いておらず、そのためにこの記事を書いていこうかなと思います。

とりあえず、説明していきます!

時間の設定

今回は日にちをまたぐときに実行する方法を書いていきます!

index.js
constfunctions=require('firebase-functions')constadmin=require('firebase-admin')constserviceAccount=require('./project-firebase-adminsdk-***.json')admin.initializeApp({credential:admin.credential.cert(serviceAccount),databaseURL:'https://project-default-rtdb.firebaseio.com'})exports.deleteQrKeyInformation=functions.region('asia-northeast1').pubsub.schedule('every day 00:00').timeZone('Asia/Tokyo').onRun(async(context)=>{// 処理の実行return0})

.pubsub.schedulecronのように指定された時刻で実行する関数を定義することができます。

every day 00:00のように時間を指定することで、この場合00:00にこの関数が実行されます。

また、return 0を記述しないと警告が表示されるので、必ず記述してください。(return trueでも警告が表示される)

テスト段階では時刻まで待つのは気が長いので、時間指定のところで* * * * *と指定すれば毎分実行されます。

ただし、毎分実行はほっておくとずっと実行されるので、1回実行したらFirebaseコンソール画面から関数を消去してください!(ログは残るので実行結果は参照できる)

このようにして指定した時刻で関数を実行することができます!

Firebase使いやすすぎてハンパない!!

以上、「ある時刻で関数を実行したい?それFirebase Functionsでやっちゃおうよ」でした!

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

Thank you for reading


【AWS】AWSのSESとnodemailerを使って、独自ドメインからメールを送信してみた

$
0
0

皆さんこんにちは!

最近AWSの様々な機能に触れるようになったのですが、何と言っても便利!!!

こういう機能無いかなと調べたらほぼ確実にある!

そんなこんなで今回はAWSのSES(Simple Email Service)を使って、nodemailerで独自ドメインからメールを送信して見ようと思います!

はじめに

独自ドメインは取得しているていで話を進めていきます。

また、SESでの設定も今回は省きます。

SESでメール送信の設定を行っていないという方は、下記の記事をご覧ください。

【AWS】AWS初心者がRoute53+SESを使って、独自ドメインでGmailからメールを送信してみた

それでは説明を見ていきましょう!

nodemailerの準備

まずは、パッケージをインストールします。

npm i nodemailer

次に、SESでメールの登録を行った際に、ユーザー名、パスワードの情報をダウンロードしているかと思います。

していない場合はもう一度設定を行ってSESのユーザー名、パスワードが記載してあるファイルをダウンロードしてください。

それらのユーザー名とパスワードを以下のusernamepasswordに定義してください。

また、ホスト名もSESで作成したリージョンを指定して定義してください。

index.js
constuserName='ユーザー名'constpassword='パスワード'constmailAddress='info@example.com'consthost='email-smtp.<リージョン(例:ap-northeast-1)>.amazonaws.com'

そして、この情報を元に以下のようにtransporterを作成します。

index.js
constuserName='ユーザー名'constpassword='パスワード'constmailAddress='info@example.com'consthost='email-smtp.<リージョン(例:ap-northeast-1)>.amazonaws.com'consttransporter=nodemailer.createTransport({host:host,port:587,secure:false,auth:{user:userName,pass:password}})

メールオプションの設定

次に、メール内容を決めます。

index.js
constuserName='ユーザー名'constpassword='パスワード'constmailAddress='info@example.com'consthost='email-smtp.<リージョン(例:ap-northeast-1)>.amazonaws.com'consttransporter=nodemailer.createTransport({host:host,port:587,secure:false,auth:{user:userName,pass:password}})constmailOptions={from:mailAddress,to:'example@gmail.com',subject:'お問い合わせ内容の確認',html:`
      <p>テスト</p>
      `}

meilOptionsにメール内容を記述してください!

メールの送信

最後にメールを送信してみましょう!

index.js
constuserName='ユーザー名'constpassword='パスワード'constmailAddress='info@example.com'consthost='email-smtp.<リージョン(例:ap-northeast-1)>.amazonaws.com'consttransporter=nodemailer.createTransport({host:host,port:587,secure:false,auth:{user:userName,pass:password}})constmailOptions={from:mailAddress,to:'example@gmail.com',subject:'お問い合わせ内容の確認',html:`
      <p>テスト</p>
      `}returntransporter.sendMail(mailOptions,(erro,info)=>{if(erro){return{error:erro.toString(),message:'To send mail is failed'}}return{message:'To send mail is successed'}})

このようにしてSESを使って、独自ドメインでメールを送信することができます。

そこまで難しくないとは思います!

メールが届かない場合は認証情報が間違っている可能性が高いです。例えばユーザー名とかパスワードとか。

それでも送信されない場合はSESでの設定を疑ってみてください!

以上、「【AWS】AWSのSESとnodemailerを使って、独自ドメインからメールを送信してみた」でした!

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

Thank you for reading

【Node.js】Express.jsからMySQLのデータ加工、ejsへの受け渡し

$
0
0

目的

現在、MySQLの店舗データを編集できるアプリケーションを作成しています。Node.jsのexpress.jsを使用し、viewにはejsを利用しています。この記事では、初学者の私がつまずいた、パラメータの受け渡しについて記述します。

ずばり「企業一覧画面から、企業に属した店舗の一覧を表示させる」処理についてです。

一連の処理は、こんな感じです

企業一覧画面(ejsで表示)
→ 店舗名のリンクをクリック
→ express.js(app.js)でデータを加工
→ 加工したデータをejsに渡す
→ ejsで表示させる

参照

Express.js(node.js)からMySQLへの接続とCRUD操作
[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する
for 文と push メソッドを使って配列要素を複数生成

環境と周辺構造

・local (mac Big Sur)
・AWS MySQL

基本となるデータベースとの接続やCRUD処理の書き方等については、リンク先の記事で作成しました。そちらを参考にしてください!
Express.js(node.js)からMySQLへの接続とCRUD操作

テーブル構造

テーブルの相関関係はこのような形です。
account_masterが企業、shop_masterが企業が運営する店舗を示しています。
スクリーンショット 2021-03-13 16.43.05.png
テーブルの関係性を簡単に表すと、
account_master.account_id = shop_master.shop_account_idです。
企業側のaccount_idは店舗側のshop_account_idと同じことを意味しています。

画面イメージ

少し雑ですが、画面のイメージは以下の通りです。
・企業 一覧画面(account_master_index.ejs)
スクリーンショット 2021-03-13 16.55.27.png
・店舗一覧画面(shop_index)
スクリーンショット 2021-03-13 16.57.24.png
企業名リンクをクリックすると、店舗一覧画面に遷移します。

ディレクトリ構造

※現在、未完成のため一部のみ記載

account_app/
├── node_modules
├── views
│   ├── account_master_index.ejs
│   ├── edit.ejs
│   └── shop_index.ejs
├── .env
├── .gitignore
├── app.js
├── package.json
└── README.md

前提

参考サイトでは、簡易なテーブルのデータで作成されていたため、企業の一覧や、店舗の一覧は簡単に表示まで出来ました。しかし、企業に基づく店舗など関係性がちょっと複雑な場合、どう表示させればよいかが全く分かりませんでした。

先に企業一覧について、次に店舗一覧について記述します。

企業一覧画面

app.js

企業一覧画面は参考サイトを元に、テーブル名、select文を変えるだけでOKでした。※記述外の設定は参考サイトを参照ください。

//app.jsの企業一覧に関する部分app.get('/',(req,res)=>{constsql="select * from account_master where is_deleted = 0";con.query(sql,function(err,result,fields){if(err)throwerr;res.render('account_master_index',{account_master:result});});});

app.getは express.js によるアプリケーションのルート( 今回は、localhost:3000 )へのGETメソッドに対応します。con.queryでデータベースから取得します。取得するデータはconst sqlで表記した select文(解約していない企業の情報すべて)です。

例外処理を記述した後、res.renderの第一引数にデータを表示させたいテンプレートを設定し、第二引数に .ejs に渡す名前を指定します。この命名により、ejs側ではresultではなくaccount_masterを使って取得したデータを利用できます。

account_master_indx.ejs

一部抜粋した記述です。

//account_master_indx.ejsの中身
    <% account_master.forEach(function (value) { %>
    <tr>
      <td><%= account_id %></td>
  ★   <td><a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a></td>
      <td><%= value.account_email.split('*') %></td>
      <td><%= value.mail_requested %></td>
      <td><%= value.is_deleted %></td>
      <td><%= value.updated_at %></td>
      <td><%= value.account_form_url %></td>
      <td><a href="/edit/<%= value.ue_account_id %>">up</a></td>
    </tr>
    <% }); %>

参考サイトはforEachを使っていたため、そのまま使っています。<% %>や、<%= %>で処理を書くのか、 HTML として表示させるかを書きます。

★ここで4行目に注目
<a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a>で企業 id のパラメータをURLに指定しています。後にこれと同じURLにする処理を app.js 内に if 文で記述します。

ここからが今回の記事の本題です

ポイントとしては以下のとおりです。
・企業に基づく店舗一覧をいきなり呼び出すのではなく、まず店舗の全データを出す
・配列を新たに作成する
・for文、if文で条件指定する
・加工した店舗一覧のデータをejs側で呼び出す

app.jsでデータを加工する

失敗した考え方
店舗一覧画面を出そうした際に、まず企業一覧画面と企業の編集画面を参考にしました。というのも、編集画面は企業のaccount_idを自然に渡せていたからです。そのため、店舗一覧画面も企業一覧と編集画面のようにaccount_idを受け渡せないかと考えました。

そもそも、この↑部分の認識が間違っており、正しくはexpress.js側で処理したデータをejsで表示させる。つまり、ejsからgetメソッドで表示させる場合はejsかた値を受け渡すなどは行わないです。

成功した考え方
いきなり企業に紐づく店舗一覧を、expressで記述しそれをejs側で表示させるのではなく、まずapp.js内で先に店舗の全データを出します。そのデータを使って、必要な情報だけを載せた配列を新たに作成します。作成した配列をejs側で呼び出し、表示させます。

店舗一覧画面

店舗一覧画面に関する記述は以下のとおりです。

app.js

//上部に宣言を記載varshopDat;//app.jsの上部で、店舗の全データを取得con.query('select * from shop_master where is_deleted = 0;',function(error,results,fields){if(error)throwerror;shopDat=results;//shopDatに代入});~~(中略)~~//企業ごとの店舗一覧を取得しshop_index.ejsで表示させるためのデータ加工app.get('/shop_index/:shop_account_id',(req,res)=>{letshops=[];//新たな配列を作成for(leti=0;i<shopDat.length;i++){//※shopDat.lendgthは要変更if(req.params.shop_account_id==shopDat[i].shop_account_id){//URLパラメータの値を条件付けvartarget_shop={//配列に入れるオブジェクトデータを定義"shop_id":shopDat[i].shop_id,"shop_name_jp":shopDat[i].shop_name_jp,"shop_name_en":shopDat[i].shop_name_en,"shop_account_id":shopDat[i].shop_account_id,"is_deleted":shopDat[i].is_deleted,"updated_at":shopDat[i].updated_at};shops.push(target_shop)//空の配列shopsに.pushで追加}};res.render('shop_index',{shop_data:shops});//for文作成した配列をshop_dataと命名});

先に shopDat を宣言し、そこにMySQLから店舗の全データを代入します。店舗一覧画面を表示させる箇所に、 shops という新たな空の配列を作成します。更にi番目の shopDat のデータを保持させる target_shop というオブジェクトを作成します。shops.push(target_shop)を shops という空の配列に、 for 文で作成されたオブジェクトを追加して、加工データを作成します。

この時req.params.shop_account_id == shopDat[i].shop_account_idではURLに渡すパラメータと企業に紐づく店舗の情報を一致させるために記述しています。※shop_account_idは企業のアカウント id と同じです。

req.paramsはリクエストされたパスからパラメータを取得するに使う文字列です。
[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する

shop_index.ejs

//店舗一覧画面に関係する部分
    <% for (let i = 0; i < shop_data.length; i++) { %>
      <tr>
        <td><%= shop_data[i].shop_id %></td>
        <td><%= shop_data[i].shop_name_jp %></td>
        <td><%= shop_data[i].shop_name_en %></td>
        <td><%= shop_data[i].shop_account_id %></td>
        <td><%= shop_data[i].updated_at %></td>
        <td><a href="/edit/<%= shop_data[i].shop_id %>">更新する</a></td>
      </tr>
      <% }; %>

企業一覧画面ではforEachを使いましたが、こちらは for 文で表記しました。これで、企業に属する店舗の一覧を表示させることができました。

小技とつまずいたポイント

・出力したいデータが正しいかどうかをHTML(.ejs)でみたい
<%- JSON.stringify(shop_data) %>と記述することで見られます!

・JavaScriptのデータは配列[ ]の中にオブジェクト{ }をもつことができる。
→ MySQLに格納されているデータはオブジェクトだったので、連想配列かと思ってしまいましたが、JavaScriptは [{ name:aaa, email:xxx@yyyy}, { name:bbb, email:yyy@xxxx}, { }....]とできるようです。(要勉強)

・forとif文をに記述するのではなく、一つづつ書くこと
→ 処理を一気に書こうとして、ほしいデータをなかなか出すことが出来ませんでした。落ち着いて出力されたデータを見ながら、一つづつ解決するほうが結果早いですね。

・app.jsにて、if文のshopDatに[ i ]をもたせること
→ iをつけることに、なかなか気がつけませんでした。

まとめ

JavaScriptを勉強しはじめて3週間ほどですが、MySQLのデータを加工を実施しました!空の配列を作って、ほしいデータを作成をすることは初めての作業でしたが、なんとかうまく出来たので良かったです。途中で、配列なのか連想配列なのか迷ったりしたため中々答えにたどり着けませんでした。これが初学者の方のためになればと思います。

また、一部未完成・不十分な記述がありますので、ご教示いただけると幸いです!

以上

Vue CLIをインストール後vue: command not foundになる

$
0
0

環境

  • macOS Catalina 10.15.7
  • Node.js 14.16.0
  • npm 7.6.3

現象

1.Vue CLIをグローバルにインストール

 $ yarn global add @vue/cli

2.インストール完了後、バージョン確認のコマンドを打つと「command not found」と言われる

$ vue --version
nodenv: vue: command not found

The `vue' command exists in these Node versions:
  10.15.1
  10.16.0

解決

以下のコマンドでPATH変数を更新

export PATH=$PATH:/Users/denis/.npm-global/bin

返ってきた…!

$ vue --version
@vue/cli 4.5.11

参考記事

node.js — Vueコマンドが見つかりません
コマンドや環境設定でよく躓いてしまうので、右往左往してこちらにたどり着きました。
ありがとうございました!!

【Node.js】パスを確認する方法(備忘録)

$
0
0

プログラミング勉強日記

2021年3月17日
Node.jsの環境変数であるNODE_PATHの確認方法をまとめる。今回はすべてWindowsで行った。

npmのPATHを確認する方法

コマンドプロンプト
$ npm bin -g

 コマンドを実行すると、ディレクトリがNode.jsをインストールしたときに自動的に設定される。そのパスが表示される。

node_modulesのPATHを確認する方法

 Nodeのサーバーを立ち上げてから、nodeコマンドで下記を実行する。

> global.module.paths

npmのPATHを通す方法

set NODE_PATH=C:\Users\フォルダ…

参考文献

【Express】環境変数とは?PATHを通すとは?けっきょく南極ローカルインストール!(Herokuコマンドでローカル起動)
Node.jsのPath(パス)を確認する方法【初心者向け】

【Node.js Express 4.x で Routing Middleware Template(pug) をつかう方法】

$
0
0

Expressでは簡単にルーティングができるが、色々方法があって忘れる。
ということでここでいったんまとめていく

Expressのversionは4系です

同じパスに対して複数のハンドラがありまとめたい
app.js
constexpress=require('express')constapp=express()app.route('app/user').get(req,res)=>{}.post(req,res)=>{}
特定のパス以下のルーティングをまとめたい
routes/user.js
constexpress=require('express')constrouter=express.Router()router.get('/',(req,res)=>{})router.get('/edit',(req,res)=>{})router.get('/delete',(req,res)=>{})
app.js
constexpress=require('express')constapp=express()app.use('app/user',(require('./routes/user')))// app/user以降のパスがroutes/user.jsで指定されているとおりに設定される

ミドルウェアの使い方

app.get()app.set()もミドルウェアに当たるため、処理をnext()で委譲できる。

・特定のパスにミドルウェアを適用
app.js
constexpress=require('express')constapp=express()functionMiddleware(req,res,next){console.log('checked Middleware function !!!!')next()}// checked Middleware function !!!! を出力後、処理をnext()で委譲しているapp.get('app/user',Middleware,(req,res)=>{res.end()}
・アプリケーションレベルのミドルウェア

委譲(next)はuse→getでもget→useでもuse→useでもget→getでもできる。
引数にnextを追加することだけ気をつける。

app.js
constexpress=require('express')constapp=express()app.use('app/user',(req,res,next)=>{console.log('middleware!!!!!!!!!!')next()})app.get('app/user',(req,res)=>{res.render('rooms',{title:'rooms'})})

・テンプレートエンジン(ここではpug)を使う方法

"view engine"をsetして、このファイルと同じ階層にviewsディレクトリを作れば、viewsディレクトリをルートディレクトリとして操作できる。

app.js
constexpress=require('express')constapp=express()app.set("view engine","pug")app.get('/room',(req,res)=>{res.render('room')// パスが/views/room.pugの場合res.render('html/room')// パスが/views/html/room.pugの場合 })
・静的ファイルも配信する

上記のままではcssやjavascriptファイルが読み込めていないので以下コードを追加

app.use(express.static(__dirname+'/views'))

・その他、app.set()でできる設定たち(他にもいろいろある)

https://expressjs.com/ja/api.html#app.setここで確認

app.set("case sensitive routing",trueorfalse)// routingの際、大文字小文字の区別を有効にするかどうかapp.set('env','production')// 環境モード 本番ではproductionにするapp.set('trust proxy',trueorfalse)// プロキシを介したHTTPリクエストでも情報を保持できるようにする

【M1ソフトウェア導入】Homebrew-node.js-npm

$
0
0

早速

●homebrew

M1 Macでのhomebrewは 公式のドキュメント で /opt/homebrew にインストールすることが推奨されている為、以下のような工程でインストールを行う。

install.homebrew
sudo mkdir /opt/homebrew
sudo chown-R$(whoami) /opt/homebrew
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C /opt/homebrew
//パスを通す
export PATH="/opt/homebrew/bin:$PATH"
//brew installの確認
% brew doctor

●node.js

install.nodejs
brew install node

//installの確認
node -v

●npm

install.nodejs
npm install-g npm

//installの確認
npm -v

世の中は本当にマイナス感情で溢れているのか?を可視化してみた

$
0
0

はじめに

「コロナ禍」と言われる言葉が生まれてから、およそ一年ほどは経ちましたね。ここ一年間ネガティブなニュースを多く耳にしたのは僕だけでしょうか?「〇〇で感染者数が過去最多」とか「コロナ禍で深刻化する〇〇」とか、不安な気持ちになるようなニュースが毎日のようにあったような気がします。実際はどうなんでしょうね。

今回は、「実際の世の中のニュースはマイナスで溢れているのか?」そんな疑問から直近1週間の景況を可視化してみようと思います。

前提

Node.js(Express)で実装

事前調査

使用API

  • News API
  • Natural Language API

News API

  • Top headlines:最新のヘッドライン
  • Everything:全ての記事
  • Source :Top headlines が利用できるニュースパブリッシャーのサブセットを返す

News API には上の三つのエンドポイントが用意されています。このうち、Everything がパラメータとして、期間を設定することが出来ます。Everythingは、感情分析の結果の推移を観測したい、という今回の要望にマッチしているため、こちらを使用したいと思います。パラメータにはこの他にも、検索元のドメインを指定したり、ソートをして人気の記事を上位に持ってきたりすることが出来るので求めたいニュースに合わせて値を設定すると良いです。

Everything のエンドポイントは日本語のニュースを検索対象にすることができません

Natural Language API

詳しくは公式をご覧ください。

https://cloud.google.com/natural-language/docs/quickstart-client-libraries?hl=ja

Natural Language API で分析できる感情は、score と magnitude の数値によって表されます。score はポジティブとネガティブを -1.0 ~ 1.0 で 表し、magnitude は感情の大きさを 0 以上で表します。これらの値は、最終的に可視化する際の指標として使用します。

開発

newsを取得する

まずは、ニュースの取得する部分の実装を行っていきます。以下の関数は日付と検索ワードを引数に指定して、人気のあるニュースを取得することができ、戻り値は後の処理のawaitで使用するためにPromiseを返すようにしてあります。

News API にはNode.js のクライアントライブラリもあるので、今回はこちらを活用して実装しました。

constNewsAPI=require('newsapi');constnewsapi=newNewsAPI('API_KEY');// ニュースの取得functionfetchNews(Date,keyword){returnnewPromise(resolve=>{newsapi.v2.everything({// optionsq:keyword,from:Date,to:Date,language:'en',sortBy:'popularity',pageSize:50,page:2}).then(news=>{resolve(news)});})}

感情分析をする

取得できたニュースの概要から感情を分析出来るように、テキストを引数とした関数を作成します。この関数は、ニュースのタイトルやURLの他に、感情分析の結果のスコアも含めた連想配列をレスポンスとして返します。こちらも、News API と同様にNode.js のクライアントライブラリを使用しています。

https://cloud.google.com/natural-language/docs/analyzing-sentiment?hl=ja

constlanguage=require("@google-cloud/language"),client=newlanguage.LanguageServiceClient();// 引数に与えられたテキストの感情を分析するasyncfunctionsentiment(text,title,url){constdocument={language:'ja',content:text,type:'PLAIN_TEXT',};varobj={"Title":title,"Url":url,"Sentence":"","Score":0,"Magnitude":0}const[result]=awaitclient.analyzeSentiment({document});constsentences=result.sentences;sentences.forEach(sentence=>{obj["sentence"]=sentence.text.content;if(sentence.sentiment.score!=0){obj["score"]=sentence.sentiment.score;}if(sentence.sentiment.magnitude!=0){obj["magnitude"]=sentence.sentiment.magnitude;}});returnobj;};

次に、二つのAPIを使用した関数を掛け合わせます。

// 取得したニュースに感情分析をかけるasyncfunctionanalysis(Date,keyword){varanalyzedList=[];varnews=awaitfetchNews(Date,keyword)for(varitemofnews["articles"]){awaitsleep()varsentenceObj=awaitsentiment(item.description,item.title,item.url);analyzedList.push(sentenceObj);}returnanalyzedList;}

この関数は、日付と検索ワードを引数とし、引数の値を使ってニュースを取得します。

取得したニュースのdescriptionを感情分析APIを使用した関数の引数として与え、一件一件評価し、帰ってきた値を配列にまとめておきます。

ここでのanalyzedListという配列には、指定した日付で取得できたニュースの情報が含まれており、一件のニュースには「タイトル」「URL」「ニュースの概要」「感情分析の結果」がまとまっています。

あとは、実際に取得する日付や期間を決めたり、analyzedListのスコアの合計の算出やソートをするなどして、実際にダッシュボードに可視化するための情報を選択していけば完成です。

今回は、ダッシュボード内で以下のことが出来るように、追加で処理を加えました。

  • 算出された1日のニュースのトータルスコアの推移を見ることができる
  • 今日の日付から1週間前までの推移を観測出来る
  • 解析期間中の、最も高いスコア(ポジティブ)の三件と最も低いスコア(ネガティブ)の三件のニュースをを知ることが出来る

最終的にレンダリングに使うコンテキストは以下のようになりました。

date:Array,// 解析した日付:Chart用totalScoreList:Array,// 解析した日付ごとのトータルスコア:Chart用picUp:Object,// スコアの上位三件&下位三件logs:Array,// 検索ワードと検索日の履歴searchKeyword:String// 検索ワード:ダッシュボードの見出し用

成果物

インターフェース部分は、BootStrapのサンプルに、作りたいもののイメージに近しいものがあったのでこちらを少しだけカスタマイズして使用しています。

検索窓にワードを入力して解析開始です。1週間のニュースを取得し、一件一件評価しているので、可視化までに時間がかかってしまうことが少しネックです。

スクリーンショット 2021-03-17 23.08.21.png

解析結果はこのようになりました。
スクリーンショット 2021-03-18 10.12.10.png
スクリーンショット 2021-03-18 10.12.19.png

直近の推移だけ見ると、ほとんど0を下回っているので、あまり良い印象では無いというが分かります。
Good Weekly Newsには「全国予防接種の日」についての記事がありますね。これは、確かにプラス面のニュースです。Bad Weekly News はバイデン政権の記事がトップに来ていました。政治の話はあまり詳しくは無いですが、執筆者の言い回し自体はかなりマイナス表現が多かったと感じるので、評価自体は妥当な値だと思います。

他のワードでも試してみます。
個人的な興味でアベンジャーズを調べてみます。(アメコミが好きなので)
スクリーンショット 2021-03-18 10.18.28.png

流石にCOVID19よりも印象は良いみたいです。
やはり今後のCOVID19に関しては、まだまだマイナスニュースを目にする機会が多くなりそうですね。

まとめ

今回は、「世の中悪い出来事ばかりじゃ無いはず!」という思いから、現状を確認するために、News API とNatural Language API で景況を可視化してみました。
検索ワードを元にした評価を可視化しましたが、ワードによって結果が大分異なるので、シンプルにヘッドラインだけでも良かったような気がします。ただ、News API のTop headlinesエンドポイントは、期間を指定できないので、また違う仕組みでの実装が必要になってきそうです。

また、TwitterなどのSNSの情報ソースを使うのも面白しいかと思います。今はSNSもみる人の感情を左右する立派な情報源なので、よりリアルの声を反映出来るのかもしれないです。

感情分析でハッピーな記事しか掲載しないニュースサイトを作る! - Qiita


Node.jsのHTTPリクエストライブラリGotの人気が上がってきてる

$
0
0

2020/2にNode.jsのrequestモジュールがDeprecated(非推奨)になって一年が経ちました。
半年前に何に乗り換えようかなと調べて、これを書きました。
https://qiita.com/hide2018/items/0507e488d91e28592ca4
当時はnode-fetchに優位性があり、僕もこれを使っています。

しかし久しぶりに調べてみると何とGotの人気が徐々に上がっており、node-fetchを抜きました。
ダウンロード数の推移がこちらです。
https://www.npmtrends.com/node-fetch-vs-got-vs-request
以前から右肩上がりで去年の12月に抜きました。
まだ上昇しています。
(そして未だにrequestを使ってる人が多い…非推奨なのに)

総合的な評価においてもGotの方が点数が高いです。
https://npmcompare.com/compare/got,node-fetch

半年前はgotは統計データ上は特に優位性のないライブラリでした。
(gotのgithubの比較表ではかなり優位に書いてありましたが。)

QiitaにGotのタグが無い程度には日本で知名度が低いです。
(無かったのでこの記事で初めてGotタグを付けました)

一体何が起きたのでしょうか?
詳しい方教えてください。

とりあえずgotとはどんなものかをウェブで調べてみました。
しかし日本語で書かれている記事は
https://kamoqq.info/post/nodejs-http-client-got/

https://www.twilio.com/blog/5-ways-to-make-http-requests-in-node-js-using-async-await-jp
くらいでした。
(あとは上記の僕のqiita記事が引っ掛かるくらい)

新しい記事が少ないので、最新のgotの解説記事を書いたら多くの人が見てくれる可能性があります。
書くなら今ですよ!

Node.js インストール時の「Failed to create the file」

$
0
0

新しいMacでNode.jsをインストールしようとして少しだけ詰まったので備忘録です。

環境

  • MacOS Big Sur ver 11.2.2
  • Homebrew ver 3.0.7
  • nodebrew はインストール済み
nodebrew ls-remote

で、以下のようにインストールしたいNode.jsのバージョンを確認します。

v0.0.1    v0.0.2    v0.0.3    v0.0.4    v0.0.5    v0.0.6

v0.1.0    v0.1.1    v0.1.2    v0.1.3    v0.1.4    v0.1.5    v0.1.6    v0.1.7
v0.1.8    v0.1.9    v0.1.10   v0.1.11   v0.1.12   v0.1.13   v0.1.14   v0.1.15

~ 略 ~

v12.16.2  v12.16.3  v12.17.0  v12.18.0  v12.18.1  v12.18.2  v12.18.3  v12.18.4
v12.19.0  v12.19.1  v12.20.0  v12.20.1  v12.20.2  v12.21.0

~ 略 ~

io@v2.0.0 io@v2.0.1 io@v2.0.2 io@v2.1.0 io@v2.2.0 io@v2.2.1 io@v2.3.0 io@v2.3.1
io@v2.3.2 io@v2.3.3 io@v2.3.4 io@v2.4.0 io@v2.5.0

今回はv12.18.4をインストールしようと思い、以下コマンドを実行

nodebrew install-binary 12.18.4

すると、

Fetching: https://nodejs.org/dist/v12.18.4/node-v12.18.4-darwin-x64.tar.gz
Warning: Failed to create the file
Warning: /Users/username/.nodebrew/src/v12.18.4/node-v12.18.4-darwin-x64.t
Warning: ar.gz: No such file or directory

curl: (23) Failed writing body (0 != 979)
ownload failed: https://nodejs.org/dist/v12.18.4/node-v12.18.4-darwin-x64.tar.gz

おおお。。。そんなディレクトリ無い!と怒られてしまいました。

・対処法1

無いなら作りましょうということで以下のコマンドを実行します。
-p オプションをつけることで、親ディレクトリも(無ければ)作成してくれます。

mkdir -p ~/.nodebrew/src

・対処法2

自分はこっちを実行してうまく行きました。調べるとNode.jsの環境を自動的に整えてくれるものらしいです。

nodebrew setup

もう一度、nodebrew install-binary 12.18.4 を実行し、

Fetching: https://nodejs.org/dist/v12.18.4/node-v12.18.4-darwin-x64.tar.gz
############################################################################################################# 100.0%
Installed successfully

うまく行きましたー

プログラミング歴半年の東大生がとりあえずECサイト作れるようになるまでに勉強したこと

$
0
0

ここ最近、React/Node/Express/MongoDB/FirebaseでECサイトが作れるぐらいには成長したので、何してきたかここに備忘録書いときます。

完全にただの日記です。悪しからず。

ECサイト作れるようになるまでの道のり・振り返り

ステップ0:プログラミング言語に触れる

たまたま取った統計データ解析の授業でR言語を使って解析してました。
振り返ると、if文, for文、型・モジュールのインポートなんてのはここで初めて身につけました。

このくらいの時期に基本情報技術者取った気がします。

ステップ1:フロントエンドに入門

  • HTML・CSS
    ウェブサイト作成チュートリアル系の本を3冊やりました。前から順にまねしていけば、それっぽいウェブサイトができるので成果がわかりやすいし、知識も身につくのでけっこう楽しいです。

  • JavaScript

    • 競プロ。Node.jsでちょっとだけ、ほんのちょっとだけやってみました。3週間ぐらいでやめちゃいましたが、後々役に立ちました。
    • 本。今度は体系的に知りたくなったので、ハンズオンJavaScriptという本を買って半分ぐらい読みました。「半分しか読めてない」ではなく「半分も読めた」とポジティブに捉えたい。Pythonの本は1/4しか読んでないので...

ステップ2: アルゴリズムをたくさん書く

HTMLでサイト書けるようになって満足していた僕でしたが、電情の授業で転機が訪れます。

2年生後半にとったプログラミング系の授業は4つ:
「ソフトウェア1/2」(Cでいろいろ作る)
「プログラミング基礎演習」(C/Pythonの文法学習)
「データサイエンス超入門」(Python/Rでニューラルネットワーク)
「Pythonプログラミング入門」(Pythonでアルゴリズム)

この中でも一番重かったのがソフトウェアの授業でした。週に一個コンソールアプリを作らされるため、毎週20時間ぐらいは使ってた気がします。物理シミュレーションとか、絵画アプリとか。けっこう必要な機能が多かったので時間はかかりましたが、思ったようにちゃんと動くのが楽しくて夢中でした。

こうして徐々に長いコードがかけるようになり、コード書くために一日中机に向かうのが苦にならなくなりました。

ステップ3: いろいろなウェブの基本概念を知る

静的なページvs動的なページ、フロントエンドvsバックエンド、クライアントvsサーバー

プログラミング始める前までは、なんもわかってなかったことたち。HTML,CSSが一通りわかるようになってきたぐらいの時に、やっと気になってググり始めました。

ステップ4: フレームワークの存在を知る

成り行きで誰かが書いた動的なサイトのコードを全部見る機会がありました。

いろいろなファイルがごちゃごちゃしてるのが衝撃的でした。「ただのウェブサイトなのにこんなにファイル作ってんの」という印象だった記憶。

後日それがCodeIgniterっていうPHPのフレームワークなのだと知り、そんなに便利なのかと思いながらも、動的なサイトを作るにはそういうのを使うものなのかと勝手に納得してました。

ついでにそのサイトを僕が修正・追記しなきゃならなくなったのでいろいろいじり、フレームワークってのはこういうファイル配置/役割分担なのかと知るいい機会になりました。

そのあと、Laravelのコードをデバッグする機会に恵まれますが、正直あんまりPHP好きじゃないです...

ステップ5: 自分もなんかフレームワークを勉強するか、とReactを始める

RailsとReactで迷いに迷って、Railsはポピュラーすぎたのを嫌がってReactを始めます。加えて、将来的にはReact/NodeでJavaScript一本でフルスタックにいけるのが魅力的でした。

なお、Pythonそんなに好きじゃないのでDjangoは最初から却下。

Reactに入門するために、いろいろ読んで、とりまやってみるという戦略を取ります。

  • 公式チュートリアルの三目並べゲーム

  • 怪しげなサイトからダウンロードした英語のチュートリアル本に乗ってた投票アプリ

  • ここでやっと公式ドキュメント

  • 大学で作ったミニゲームをReactに移植してデプロイしてみる

  • 海外の大学のオープンコース教材
    これはまじでおすすめです。まだ全部読んでないけど...。あとで絶対全部読みます
    目次:

    • Introduction to React
    • Communicating with server
    • Programming a server with NodeJS and Express
    • Testing Express servers, user administration
    • Testing React apps
    • State management with Redux
    • React router, custom hooks, styling app with CSS and webpack
    • GraphQL
    • TypeScript
    • React Native
    • CI/CD

ステップ6:サーバーサイドもやってみる

サーバーサイドどうしようか迷ったけど、Node/Expressを選びました

  • 某有名プログラミング教育系サイトに登録
    • 無料キャンペーンやってたので、ReactとJavascriptとNodeの関連コース一週間で全部やってさっさっと退会することで課金0で済みました。

ステップ7:えいや!とフルスタックでECサイトを作ってみる

もちろん自分で無からECサイトを錬成することはまだできるようなレベルではありません...

Udemyがセールやってて、24,000円のコースが1,500円で思わず買ってしまいました。
そのコースの通りに勉強していると、いつの間にかECサイトの作り方が本気で理解できちゃうという優れもの。(宣伝じゃないです)

軽いインドなまり英語のおっさんの動画講義(43時間)でしたが、まじでわかりやすかったのでお勧めです。
なまりは聞いてるうちに気にならなくなります。英語の勉強にもなって一石二鳥。

これ:React Redux Ecommerce - Master MERN Stack Web Development

よう考えたら43時間って東大の二コマ授業一セメスター分ですね。

続く

2021年3月時点までにやってきたことはこれでだいたい全部です。

案外少ないですね...

これからも、時間をつくってはいろいろオリジナルに開発していこうと思います。

思い付きで書いた記事なのでここまで見ていただいた方はいないと思いますが、もしもなにか参考になるようなことをかけてたら幸いです。

Node.jsについて / JavaScriptの基本(メモ)

$
0
0

概要

Node.jsの特徴や書き方
JavaScriptの基本の文法を忘れないために記述していきます。

環境

macos
macos
macos

その他 各バージョン

version
Homebrew3.0.5
Nodebrewv8.9.4
Node.jsv14.16.0
npm6.14.11

Node.jsについて

Node.jsの特徴というか重要?

 1. イベントループによる平行処理を行う
 2. npm (Node Package Manager)
 3. モジュールシステムについて
 4. Universal JavaScript、Universal Web Application
 5. Node.jsとECMAScript(ES6)

Node.jsの対話型インタプリタ(Read-Eval-Print Loop: REPL)機能

Node.jsでREPL機能を使用する方法(割と便利なやつ)

#zshでの記述例

% node #nodeと入力しEnter
Welcome to Node.js 起動しているバージョン.
Type ".help"for more information.
># 上記のようになれば記述可能状態である#終了する場合は Ctrl + D もしくは下記のように記述
% .exit

Node.jsでのJavaScriptファイルの使用方法

ターミナルからフォルダ及び.jsファイルを作成してそれを実行するまでの手順

username % cd desktop # まずわかりやすくデスクトップに移動
username desktop % mkdir sample # サンプルフォルダを作成
username desktop % ls# デスクトップにちゃんと出来てるか確認します
sampel # デスクトップにあるものが表示されます

username desktop % cd sample # sampleフォルダに移動します
username sample % touch test.js # test.js ファイルを作成します
username sample % vi test.js # test.jsの内容を変更します# vi ~のコードを打つと下記のような画面になるので キーボードの i  を押します
//////////////////////////////////////////
~
~
~
"test.js" 1L,28C → iを押すと右記に変化します → -- INSERT --# 入力できるよ!っていう状態です
//////////////////////////////////////////
# 一行目に記述
console.log('Hello World')

ESCボタンをおして :wq と入力しEnterを押すと元の画面に戻ります。

# node jsファイル名で実行
username sample % node test.js
Hello World

# と上記のようになればsampleフォルダのtest.jsが読み込まれた事になります。 

JavaScriptの基本(変数宣言・関数宣言)

基本的な記述方法を記載

sample.js
// 変数宣言letfoo=0// 変数 (変数の書き換えが可能)constbar=1// 定数 (変数の書き換えが不可能)// 関数宣言functionsample(i,j){returni+j}// 基本型constsample=function(i,j){returni+j}// 変数・定数への割り当てが可能// アロー関数式(ラムダ式みたいなやつ)constsample=(i,j)=>{returni+j}// 基本型constsample=(i,j)=>i+j// {}外すとreturn省略できるってよconstsample=i=>i+3// 渡す値が一つだったら()も省力できるってよ// *注意点* 関数宣言は巻き上げられるけど関数式は巻き上げられないってよconsole.log(add(1,2))// 3console.log(add2(1,2))// エラーfunctionadd(a,b){returna+b}constadd2=(a,b)=>a+b

他にも配列やオブジェクトについての解説も一通り本には載ってるので
JavaScript初心者でもNode.js興味のある方や勉強したい方には結構おすすめです!

参考

ハンズオン Node.js

DynamoDb:ローカル環境構築(その2:GUI管理ツール)

$
0
0

aws公式サイトで「NoSQL Workbench」というデータベース管理GUIツールがあるが、テーブル作成・変更、データ登録・更新しづらいので、dynamodb-adminの構築方法を紹介します。

dynamodb-adminの詳しい情報は、以下を参照してください。
https://www.npmjs.com/package/dynamodb-admin

dynamodb-adminをインストール(グローバルで)

  npm install dynamodb-admin -g
※1 もしstrict-ssl問題が発生した場合、下記コマンドで無効にして、再度インストールしてください。
  npm config set strict-ssl false
※2 root権限が持ってなかったら、先頭にsudoを追加してください。

DynamoDBのエンドポイントを環境変数に設定

export DYNAMO_ENDPOINT=http://localhost:8000

起動コマンド

  dynamodb-admin

DynamoDBを起動して下記のURLをアクセス。

Viewing all 8823 articles
Browse latest View live