20211014のJavaScriptに関する記事は22件です。

【フォーム】追加ボタンを押して関連した入力欄2つを同時に増やしていく方法

はじめに 今回以下のようなフォームは作ったので、備忘録として残しておきます。 HTML部分 create.brade.php <label>{{ __('材料') }} <a onclick=add() class="btn btn-sm btn-light">+追加</a> <div id="input_plural"> <div class="d-flex"> <input type="text" class="form-control mb-1" name="ing-name-1"> <input type="text" class="form-control mb-1" name="ing-size-1"> <input type="button" value="削除" onclick="del(this)"> </div> </div> </label> javaScript部分 main.js let inputPlural = document.getElementById('input_plural'); var count = 2; function add() { let div = document.createElement('DIV'); div.classList.add('d-flex'); var input = document.createElement('INPUT'); input.classList.add('form-control'); input.setAttribute('name', 'ing-name-'+count); div.appendChild(input); var input = document.createElement('INPUT'); input.classList.add('form-control'); input.setAttribute('name', 'ing-size-'+count); div.appendChild(input); var input = document.createElement('INPUT'); input.setAttribute('type', 'button'); input.setAttribute('value', '削除'); input.setAttribute('onclick', 'del(this)'); div.appendChild(input); inputPlural.appendChild(div); count++; } function del(o) { o.parentNode.remove(); } おわりに bootstrapを使ってちょっぴり整えているので、その点はご了承ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

onchangeイベントで確認ダイアログの結果に応じてキャンセル with jQuery

結論 Deferredとクロージャ使った。 もっとベターなやり方は山ほどありそう。 なりゆき やっほー☆フロント側をjQueryだけで開発しているみんな、こんにちは! なんでこんなことになっているんだろうね!?うらむならプロジェクトをうらもう⭐️ 突然だけど、プルダウンの変更時、変更前の情報を知りたいと思ったことはないかい!? んー、そう? ぼくはあります!今まで何度もありました!ていうか今日もありました! んでまあ、過去の実装を参照してもいいんですけど、今の自分ならどうするか、って考えてあんまりみないことにしました。jQueryのみでなんとかしていることから分かる通り、プロジェクト自体が緩いので許される・・・・・・と思いたい。 考えたこと DOM側に情報を持たせる 多分、今までも大体これでやっていたはず。 確定したタイミングで<input type="hidden" id="hidLastValue" />みたいなやつに値を設定するとか。 全然悪くはないし、手っ取り早いし、いいとは思う・・・・・・。 でも責務がぶれてるかなあ・・・・・・? HTMLは単なる構造化文書であって、サーバー側との送受信項目はまだしも、クライアント側のみで使う値をhiddenやdata-*属性で持たせる・・・・・・。 いや、悪くはない!ぼくも結構その手は使っている! でも、他に方法はないかなあ・・・・・・? 微妙なプロパティの値を使う 実際全く微妙じゃないかもしれないけど! 調べたら結構あったんですよね、jQueryのこのプロパティは前の値で、DOM要素のこれは今の値、みたいなやつ。 いや、いいと思うんですよ。 でもそれ、コード自体が説明的じゃないよな・・・・・・・。 わたしがみたやつのイメージだと、ほんとわずかな書き方の違いだけでbefore-after切り分けていて、え、これ調べなきゃ前後比較してるってわかんねーだろ、みたいな。 あとそこまでいくと環境依存入らない?みたいな。 わたしなりに頑張る javascriptで値保持、と言えばグローバル変数。ほんとそれ、ではあるんだけど、書き換え可能。さっきのhiddenとかdata-*もそうだけど、ユーザーが容易に書き換えできるのは、もちろん要件次第ではあるんだけど、どうなの?っていう気持ちが強い。 バニラなjsでカプセル化っぽいことしたかったら、わたしが知る限りはクロージャ。 クロージャ、要するに参照されているかぎり変数生きてる、みたいな技。 以下、思い出しながら書いているので間違っていたらごめんなさい。 letとか使ってみたい $(document).on('change', '#selectElem', (function() {})( var lastValue = document.getElementById('selectElem').value; return function(e) { var def = new $.Deferred(); // ここのスペル自信ない:) confirm(function(result)) { result ? def.resolve() : def.reject(); }); // ここの確認処理でYes/No判定 def.promise().done(function(){ lastValue = e.taget.value; /* Yesのときは流れのまま */}) .fail(function() { $('#selectElem').val(lastValue); /* 元に戻す */ }); } ));
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScriptのメモ】OKやキャンセルのダイアログを表示する関数

今回は、JavaScriptで使用される基礎的なダイアログを表示する関数を紹介します。 confirm() JavaScript confirm('文字列') confirm()においては、戻り値が意味を持ちます。 戻り値はTrue、Falseの二種類で OKを押せばTrueでキャンセルを押せばFalseを返す仕組みになっています。 confirm()とalert()の違いは、ボタンの数 alert()はOKだけですが、confirm()はボタンがOKとキャンセルの二つです。 prompt()はボタンがOKとキャンセルそして、テキスト入力エリアが表示されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Qiita APIを使う練習 #1 特定の検索ワードで記事を取得してみる

はじめに プロトアウトスタジオという学校に入った。 プログラミングと企画のスキルを磨いてモノづくりにチャレンジしようという、 日々インフラシステムを保守しているだけのシステム会社9年目の人間から見れば なんとも眩しくて近寄りがたい学校である。 とりあえずの入門としてプログラムに触れてみようとなり、 何かしらの成果物を作らねばと、今私はQiitaAPIを使ってテキトーにプログラムを動かそうとしている。 まじでなんもわからん。 せめて興味のあるものに絡めよう。好きなものとか。 趣味は麻雀と競馬。 なんかアルゴリズムとか難しそうだし(知能指数2)、麻雀に関連する記事とかを引っ張ってこればいいか。 考察とか分析とかはできないけど、プログラムを動かした記録があればいいんだろう。 ・・・というぐらい意識が低い。同期のみんな安心してほしい、私が劣等生だ。 やったこと ・検索クエリに「麻雀」というワードが含まれる記事を取得する  〇取得する項目   -タイトル   -URL   -作成日付   -LGTM数(普通にいいねって言えばいいのに) GET /api/v2/items でやってみた。 環境 ・Qiita API ・Visual Studio Code ・JavaScript ・Node.js サンプル GET /api/v2/itemsって、記事の一覧を作成日時の降順で返しちゃう。 いいね数で降順にしたかったんだけど、うまくできなかった。 何もわからない人間はどうしたかというと、1項目ずつプログラムを叩いてExcelで集計した。 const axios = require('axios'); async function main() { let response = await axios.get( 'https://qiita.com/api/v2/items?sort=count&page=1&per_page=100&query=' + encodeURIComponent('麻雀') ); for (let i = 0; i < response.data.length; i++) { console.log(response.data[i].title); //記事のタイトルとってる /// console.log(response.data[i].url) //記事のURLとってる /// console.log(response.data[i].created_at) //記事の作成日時とってる /// console.log(response.data[i].likes_count) //記事のいいね数 } } コメントを消しては実行を繰り返し、出てきたのをぺたぺたエクセルに転記→ソート。 私「これ絶対もっといいやり方あるだろ…」 結果 一覧化したものたち。結構あった。 タイトル いいね数 更新日時 URL Pythonライブラリの「麻雀(mahjong)」って?? 487 2020-01-19T02:41:22+09:00 https://qiita.com/FJyusk56/items/8189bcca3849532d095f ネット麻雀(雀魂)をOpenCVと機械学習で自動化した話 328 2020-08-12T14:48:42+09:00 https://qiita.com/hiro0156/items/51ab267f4f47f2f8fe76 【最速】既婚子持ち社会人のクラウド初心者でも、1ヶ月半でAWS資格11冠制覇できる方法 322 2021-08-01T18:38:52+09:00 https://qiita.com/mrpepper/items/64039b828c82e12ad35f エクストリーム「人類最強ボードゲームAI」AlphaZeroアルゴリズム入門 229 2020-07-10T06:17:01+09:00 https://qiita.com/yuto-ktok/items/8c305b0c9fad5465c517 30歳目前となったので、データサイエンティストとしての半生を振り返る 229 2019-12-25T12:21:40+09:00 https://qiita.com/tomoyuki-murakami/items/4a7baca38defbac9d87c 【大卒?院卒? 結論ホイ卒系だから】元光通信の営業マンがweb開発&データ分析で起業後、1年経過して伝えたいこと。 223 2020-06-04T05:06:34+09:00 https://qiita.com/LightSign/items/180e068d0703df5690d7 新型コロナの自宅待機中に、ビデオチャットしながらゲームで遊べるサービスを作った話 175 2020-05-21T08:51:33+09:00 https://qiita.com/aitaro/items/8a97d320f5586c6e7bb6 プログラマにも読んでほしい「QC検定にも役立つ!QCべからず集」 165 2021-03-04T20:40:20+09:00 https://qiita.com/kaizen_nagoya/items/d8ada7b7fceafe2e5f0e 【Unity】新規ゲームのUI開発で気をつけた39のTips前編 131 2020-12-01T10:55:11+09:00 https://qiita.com/ohbashunsuke/items/0570234362e2e45c0011 「kaggleで勝つデータ分析の技術」を実践してKaggleで勝つ - Kaggle M5 Forecasting Accuracy 59th (of 5558) 解法まとめ 79 2020-07-02T01:00:23+09:00 https://qiita.com/takaaki_inada/items/3f822737cf306a7bbce9 AtCoderで黄色上位になるまでにやったこと 43 2020-12-04T12:42:15+09:00 https://qiita.com/trineutron/items/f2d676d669db352260e7 【技術書典9】ゲーム関連技術頒布物(新刊)まとめ (2020/9/16 22:00 時点) 32 2020-09-11T23:02:08+09:00 https://qiita.com/takehara-ryo/items/5f535164ee46f7e0c52d 【麻雀AI】天鳳鳳凰卓の9年分のプレイをCNNを用いたNNモデルに学習させてみた 27 2020-12-11T15:50:34+09:00 https://qiita.com/neuzen-ryuki/items/48fa468fa0b1c502ed1e 文系でもソフトウェアエンジニアになれますか? 26 2020-12-02T00:36:44+09:00 https://qiita.com/odmishien/items/c0fa9c30cb16a3edc90a Pythonで麻雀を作る#1 17 2021-08-26T03:06:22+09:00 https://qiita.com/JuneOgust/items/25f9ca05ee068a1c611a もっと日本語でSwiftプログラミング(麻雀編) 16 2020-06-22T11:53:34+09:00 https://qiita.com/codelynx/items/df2ba0b755613bf17525 Microsoftの最強麻雀AI Suphx の論文ざっくり日本語訳(各種評価と結論) 15 2021-06-16T18:43:41+09:00 https://qiita.com/Intel0tw5727/items/e7625fb005982d225ea2 テンプレートマッチング・CNNで麻雀対局中継の手牌を検出しました。 15 2020-03-04T12:06:55+09:00 https://qiita.com/smishima/items/4f79eeb98537bd133e2a Microsoftの最強麻雀AI Suphx の論文ざっくり日本語訳(導入と概要まで) 13 2021-06-15T10:34:58+09:00 https://qiita.com/Intel0tw5727/items/e122197b5a2958a22b34 麻雀の多面待ちのパターンを全て求めてみた 13 2021-01-23T16:09:54+09:00 https://qiita.com/firedial/items/567335167fef29f62b2d Microsoft Ignite Keynoteとtogetherしようぜ with Elixir 11 2021-03-31T02:44:50+09:00 https://qiita.com/torifukukaiou/items/64616a2999f8628a10ed GROWI開発の知見でLINE_bot作ってみた 10 2020-12-10T17:03:26+09:00 https://qiita.com/yusuketk/items/2ab0bacc1725f94e3047 NHKの番組をゆるく検索できる PowerAppsでつくってみた 10 2020-12-09T20:15:27+09:00 https://qiita.com/MiyakeMito/items/a0c6b8b293463392fd35 天鳳個室の自動成績管理アプリをLINE botとPythonで作る その① 10 2020-06-02T01:06:52+09:00 https://qiita.com/all_green/items/4c5f4bc1a2044b00d2f8 二人零和有限確定完全情報ゲームのつくりかた 9 2020-12-24T18:52:50+09:00 https://qiita.com/Rasshiine/items/6fa46ce8be9cdef5d196 NeosFesta2を支えるダイナミックスポーンシステム 8 2020-12-14T14:43:38+09:00 https://qiita.com/rhenium_vrc/items/c8933e576039f783ddd8 [前編]ancestryを用いた多階層windowの作り方[ancestry説明編] 8 2020-03-12T21:31:57+09:00 https://qiita.com/naoya97316/items/cd035d76d7f9be2660b4 現場で役に立つ!最小限の修正で仕様変更に対応する方法(Ruby) 8 2019-12-05T22:57:31+09:00 https://qiita.com/lobin-z0x50/items/1d7e22d711940f5f4e19 ぴよログのデータから育児のつらさを可視化してみた 7 2021-02-01T22:14:43+09:00 https://qiita.com/yakipudding/items/11223f12a843e4399300 はじめてのLogiX(WebSocket編) 7 2020-12-24T09:47:36+09:00 https://qiita.com/garyumaru/items/a6860409996f8eaa16fd 新卒エンジニアに薦めたい非エンジニアの本 7 2019-11-22T08:41:07+09:00 https://qiita.com/Sunochi/items/1ddec89492855f0eaf7b 入社から1ヶ月で Claris FileMaker オンライン学習 初級編を観た話 6 2021-04-26T15:28:59+09:00 https://qiita.com/s_yarma/items/8cd4a26a71eefcb80d3f 謎に包まれたVRマニュピレーターという職業 VRカタリアウ2020 #vrk5 オペレート後日譚 6 2020-12-13T17:30:28+09:00 https://qiita.com/kmizuno0211/items/4db93080d0eb2045f140 フリマアプリのカテゴリ機能〜gem : ancestryを使用〜 6 2020-05-01T12:24:49+09:00 https://qiita.com/renaboo/items/e9ad2a1d2033cc23c0d8 はじめてのLogiX 5 2020-12-17T01:28:15+09:00 https://qiita.com/garyumaru/items/10c8948821b43016451b 【NeosVR】面白い所と楽しみ方 5 2020-12-05T13:30:55+09:00 https://qiita.com/spoil/items/e090005a407ab3cba589 Tweepyメモ 5 2020-10-29T08:40:30+09:00 https://qiita.com/kaonashikun/items/fc5b54c0a9f98bebb518 【個人開発】初めてWebサービスを作った 4 2021-01-24T21:28:36+09:00 https://qiita.com/kaonashikun/items/be15de49abfe1726a1d9 4回目の緑になるつもりが、灰色に落っこちました 4 2020-12-22T23:46:25+09:00 https://qiita.com/TheYoshipiro/items/df76b1bb6a58f8cb756d 【第1回】初心者二人で0から麻雀アプリ開発 4 2020-10-26T23:03:34+09:00 https://qiita.com/RTkd59/items/3968bff9a1d9982cd1db Pytorchで日経平均の予測~幕間~ 4 2020-09-17T15:58:27+09:00 https://qiita.com/hoolly728/items/9151e2cd65485988610b jQueryとancestryを使ったカテゴリー選択機能(Ajax) 4 2020-08-12T17:43:39+09:00 https://qiita.com/misioro_missie/items/175af1f1678e76e59dea 【個人開発】Flutterで四則演算だけの低クオリティーiOSアプリを作ってみた【リリースするのが大事って教わったから...】 3 2021-04-13T23:22:48+09:00 https://qiita.com/bytheway811/items/f8cb3fb70ce9d85a0e38 Pythonで麻雀を打ってみた(一人麻雀編) 3 2020-12-31T23:52:57+09:00 https://qiita.com/OkNCTer/items/9de8d20a3dede9a4daa2 はじめてのLogiX(HTTP GET/POST編) 3 2020-12-24T19:03:26+09:00 https://qiita.com/garyumaru/items/8337c93df0f11b3e8efa 技術書典9「機械学習、データ分析」系の新刊リスト 3 2020-09-22T13:32:22+09:00 https://qiita.com/tomo_makes/items/9073533541e83db72fbd Discord でバーチャルオフィスを作る 3 2020-07-16T16:04:33+09:00 https://qiita.com/hkanamaru/items/128f5a2ae6dfa829da33 雀士適性検査ゲーム 3 2020-07-07T01:06:29+09:00 https://qiita.com/FKazuki/items/b6e985d1e857bb884bf8 【Rails】多階層カテゴリー実装〜ancestry導入〜 3 2020-06-15T23:58:57+09:00 https://qiita.com/nishiyan0129/items/aca2464abefb22fc4491 [麻雀]一人麻雀攻略! 和了確率の計算アルゴリズム 3 2020-03-19T21:42:23+09:00 https://qiita.com/tomohxx/items/01e73efc976f88d3b71a Pythonで麻雀を作る#2 2 2021-08-31T06:54:32+09:00 https://qiita.com/JuneOgust/items/64215dbe88f551810e36 Microsoftの最強麻雀AI Suphx の論文ざっくり日本語訳(各種アルゴリズムからpMCPAまで) 2 2021-06-15T18:59:42+09:00 https://qiita.com/Intel0tw5727/items/e948e23a6a6d6c961c35 清一色の手牌は何通りあるか(13重ループ、再帰、itertools、包除原理) 2 2021-05-24T00:50:37+09:00 https://qiita.com/hibit/items/4de65bd1338bf68fb3d0 一年の記念日をjson化した 2 2021-03-11T10:03:31+09:00 https://qiita.com/hatt_takumi/items/184712e8723acd023c79 天鳳個室の自動成績管理アプリをLINE botとPythonで作る その② 2 2020-06-13T16:49:32+09:00 https://qiita.com/all_green/items/7d33ad7472a7a3d4aba6 [Swift]R.swiftで生成するViewControllerのinitにパラメータを渡す 2 2020-05-31T03:29:01+09:00 https://qiita.com/nwakabayashi63/items/3c1b6cd3dbf0585ec9a7 【ステイホーム】zoom麻雀用Webサービスを1.5日で作った話【お家で過ごそう】 2 2020-05-17T21:37:11+09:00 https://qiita.com/pon-wchoco/items/21f7b25cc5e396cf5509 Choices.js + fetchAPIでフィルタ付き動的セレクトボックス [脱jQuery] 2 2020-02-09T07:29:29+09:00 https://qiita.com/DevNururi/items/83818eb8380c06610314 VirtualBox(5) VirtualBoxのHaikuにアプリをインストール 2 2020-01-15T15:42:40+09:00 https://qiita.com/FuRuYa7/items/80d4f549504c00449e8a 「みなさんはどうやってプログラミングを学んできましたか?初めてのプログラミング言語や、きっかけはなんですか?」 2 2019-12-01T20:57:40+09:00 https://qiita.com/bg1bgst333/items/737f4437363fe0452bc3 Pythonで麻雀を作る#2.5 1 2021-08-31T19:23:01+09:00 https://qiita.com/JuneOgust/items/7051da9b6d87fa074f50 【Vue Firebase】麻雀成績管理アプリ「Mahjanager」をリリースした話【個人開発】 1 2021-06-12T10:22:33+09:00 https://qiita.com/samurai_se/items/59a56d102032ea2214a1 C++初心者が待ち牌検出してみた 1 2021-04-28T17:32:04+09:00 https://qiita.com/mtau/items/5db38e31b084b0150f2e バルクインサートでユニーク制約に引っ掛かるとIDが飛び飛びになる問題 1 2021-03-04T18:25:08+09:00 https://qiita.com/wonder_boooy/items/aa9ce720ff224adfab33 大容量CSVを編集するためにPowerShellが使える 1 2020-12-10T21:14:53+09:00 https://qiita.com/gat3ta/items/eca0c0baab2a021c5c6b 【第4回】初心者二人で0から麻雀アプリ開発 1 2020-11-19T23:26:31+09:00 https://qiita.com/dashun814/items/ab4f7b668fb12cacd2f8 文系卒開発初心者がまとめるGitHubの使い方 1 2020-11-07T19:57:27+09:00 https://qiita.com/RTkd59/items/078d7c31a5cd61ac3770 【第2回】初心者二人で0から麻雀アプリ開発 1 2020-11-03T13:42:44+09:00 https://qiita.com/dashun814/items/9f8f0d78917456ce1b6d なんかあんまり関係なさそうな記事も引っかかるのはなぜだ。 Pythonで麻雀をつくるとかは結構面白かった。さっぱりわからんけど。 点数計算とか、シャンテン数把握とか、着順がそのままデータ連動されるとかは面白いかもしれない。 やっぱり作るならせめて興味のあることにしたいよね。 終わりに はじめてに近いプログラミングで未だによくわかってないけど、 とりあえずアウトプットはできたからいいよね。。もう、ゴールしてもいいよね。。 JavaScript、難しいけどスマホアプリとか作れるみたいだし、夢が広がる。 半年間頑張って何かしら形を出していきたいと思うんですが、続けられる自信はないです。 Qiitaの記事と退職届、どっちが早く書きあがるかって感じ。 ここまで読んでいただいてありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コロナ禍前後で、クラウドファンディングへの関心は変わったのか?

はじめに はじめまして、JavaSqript初心者です。 恥ずかしながらAPIについても数日前に初めて意味を知った素人。当然ながらQiitaAPIに触れたのも初めて。知識を武器にできるよう、楽しみながら学んで行きたいです。 目的 どうせやるなら自分が好奇心を持てるものを。 思い浮かんだのは、最近よく耳にするクラウドファンディング(以下、CF)について。 数年前に小学校の同級生が、子供の頃からの夢を実現させるためCFを達成させ企業した話を聞き、とても夢があると感動した。 2021年10月現在はコロナ禍真っ只中。私がCFで初めて支援したのも昨年コロナが蔓延し始めた頃だった。 ちなみに当時支援したのは、こちら。 プリントごっこを思い出す、昔懐かしい印刷が楽しめる印刷所。シルクスクリーン発注をして自分で手刷り印刷もできるので、いつか利用してみたいなぁと思っていたところ、経営難となり経営存続を賭けてCFが発起された。(結果は是非、リンク先からご確認を!) 同じようにコロナの影響でCFに救いの手を伸ばした企業、個人も多いはず。 Qiita内でも、コロナ禍前後(2020年3月)でCFに関する変化があったのか、調べてみる。 使用した環境 Visual Studio Code 1.61.0 Node.js 7.24.0 確認方法 やりたいことは、以下の3つ。 本文に「クラウドファンディング」を使用している記事を検索 検索した記事の作成日を集計 コロナ前後(2020年3月前後)で記事数に変化があるのか確認 本文に「クラウドファンディング」を含む記事を検索し、作成日を出力する まずは単純に、Qiita内で本文に「クラウドファンディング」という単語を使用している記事の情報を抽出する。 出力にcreated_atを指定して、記事の作成日付を出力する。 // axiosモジュールを読み込む const axios = require("axios"); // main()関数を定義する async function main() { // QiitaAPIで本文に「クラウドファンディング」を含む記事を検索 let response = await axios.get( "https://qiita.com/api/v2/items?per_page=100&query="+encodeURIComponent("クラウドファンディング") );   // 結果を出力(繰り返し) for (let i = 0; i < response.data.length; i++) { console.log(response.data[i].created_at); } } main(); 結果(失敗) pageのパラメータ指定なしでper_page=100と記載したため、現時点から過去100件分しかデータが取得できなかった。 これだと、2018年12月からのデータしか取れていない。そのため8件と極端に少なくなっている。データとして非常に気持ち悪い結果になった。せめて2018年について、1年分データを取りたい。 件数を制限することなく、2018年1月から情報を取得するにはどうしたらよいか? 本文に「クラウドファンディング」を含む記事の総件数を確認する 取得件数の上限が100件だと、件数が取得しきれないということが分かった。 そもそも「クラウドファンディング」で検索した場合の関連記事は全部で何件あるのか? 出力指定に、console.log(response.headers); を指定。 返ってきたデータからtotal-countを出力し、検索対象の総件数を確認する。 Total-Countについて また、ページを指定できるAPIでは、要素の合計数が Total-Count レスポンスヘッダに含まれます。 // axiosモジュールを読み込む const axios = require('axios'); // main()関数を定義する async function main() { // QiitaAPIで「クラウドファンディング」という単語で記事を検索 let response = await axios.get('https://qiita.com/api/v2/items?query=' + encodeURIComponent('クラウドファンディング') ); //取得した記事の情報を抽出 console.log(response.headers); } main(); 2021年10月現在、185件の記事があることを確認できたので、次は先ほど取得し損ねた2018年分が丸っと入ったデータを取得する。 指定した年月以降のデータを取得する 今回取得したいデータはMAXで185件ということを確認したので、出力上限を2ページ(200件分)に設定する。 2018年1月分から取得したいので、encodeURIComponent('>=2018-01')を指定する。 // axiosモジュールを読み込む const axios = require("axios"); // main()関数を定義する async function main(page) { for(let page=1; page<=2; page++) { //「クラウドファンディング」という単語を含み、2018年1月~現在の期間に作成された記事を検索 let response = await axios.get( 'https://qiita.com/api/v2/items?page=' + page + '&per_page=100&query=' + encodeURIComponent('クラウドファンディング') + '+created:' + encodeURIComponent('>=2018-01') );   // 結果を出力(繰り返し) for (let i = 0; i < response.data.length; i++) { console.log(response.data[i].created_at); } } } main(); 取得の上限を200件にしたが、もっと件数を取得したい場合は、page<=2 の数字を変更する。 結果 ・2018年~2021年10月現在の集計結果 取得したデータ結果を確認すると、2018-01-01のデータが含まれているので、データを上手く取得することができた。 グラフ化してみても、2020年で件数が確かに増えている。 しかし正直もっと分かりやすく差が出るかと思っていたが、それほど差がないようにも見える。(2018年の件数が予想よりも多かった。) ・2020年の集計結果 2020年のデータを月単位で比較すると、分かりやすく3月(コロナ後)で数が増えていることが確認できた。 すべてのデータを取得する せっかくなので、2018年以前も含めたすべてのデータも取得する。 先のコードの年月指定の行を削除して実行。 // axiosモジュールを読み込む const axios = require("axios"); // main()関数を定義する async function main(page) { for(let page=1; page<=2; page++) {   //「クラウドファンディング」という単語を含む記事を検索 let response = await axios.get( 'https://qiita.com/api/v2/items?page=' + page + '&per_page=100&query=' + encodeURIComponent('クラウドファンディング') );   // 結果を出力(繰り返し) for (let i = 0; i < response.data.length; i++) { console.log(response.data[i].created_at); } } } main(); 結果をグラフ化すると、CFへの関心度が如実に表れているように見える。 CAMPFIREによれば、日本で初めてのCFは2011年9月とのこと。(参考:クラウドファンディングのはじまり) Qiitaで「クラウドファンディング」文言を含む記事が初投稿された2013年は、CFサービスMakuakeが提供開始した年でもあり、世間的にCFに関する認知度が高まったと推測される。 月別の比較結果 ちなみに2013年から2021年10月現在時点で「クラウドファンディング」文言が入った記事の投稿数が一番多かった月は、ダントツで12月だった。 実際の記事を確認すると、文言がタイトルに入ったリンクを貼った記事が複数投稿されているのでその影響もあるようだが、それにしても突出して件数が多いので興味深い。 12月になるとCF関連で何かあるのだろうか? 結論 コロナ後に、CFへの関心は高まったと言える。 12月になると、Qiitaに「クラウドファンディング」の文言が含まれた記事が多く投稿される。 最後に データの集計や分析をするのに、QiitaAPIを活用して効率よくデータが取得することができた。 今回はデータの加工については手作業で実施してしまったが、csv形式での出力、グラフ化、日付のFROM TOで指定、等を自動で取得できると理想的である。 データを数字としてだけでなく、グラフや表で可視化すると新たな発見があったりして、とても興味深かった。 数字に変化があったとき、世間もまた変化していて、それがどんなものなのか調べたり考えたりすることで思わぬ気づきがあると知ることができた。比較数が少ないとそれほど差がないように見えるが、比較対象を増やすことで緩やかな変化に気づくこともあるというのも、大きな発見だった。 2021年データについてまだあと2ヶ月分のデータが空白なので、2022年になったら改めて取得して比較したい。 結果が今から楽しみである。 参考記事 QiitaAPIで2020年投稿のストック数が多い記事のタグ情報を調べてみた Qiita APIで投稿一覧を取得するときに、検索クエリをORでつなぐ時の注意点
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FirebaseのFirestore v9でサブコレクションを取得する

FirebaseとReactでアプリを作成していたときに、Firestore ウェブバージョン9のサブコレクションを取得する方法を記載した記事が中々なかったのでまとめます。 サブコレクションとは? Firestoreはリレーショナルデータベースとは構造が違い、ドキュメントとコレクションの組み合わせで構成されています。 リレーショナルデータベースとFirestoreの違い とあるユーザがいてそのユーザに紐づくブログ記事(複数)があった場合、 リレーショナルデータベースでは「ユーザ」テーブルと「ブログ記事」テーブルがそれぞれあり、ブログテーブルにユーザIDを持つなどして「ユーザ」とそれに紐づく「ブログ記事」を定義すると思います。 Firestoreでは、複数の「ユーザ」というコレクションがあり、個々のユーザの中にそれぞれサブコレクションとして「ブログ記事」があるというイメージです。 FireStoreからサブコレクションを取得する方法 上記で書いた通り「ユーザ」と紐づく「ブログ記事」があるという想定で、ユーザに紐づくブログ記事を取得してみます。 以降のソースは全て、以下の通りinitializeやgetFirestoreでdbを取得した前提のソースです。 ここのdbの取得の方法もあまり記載した記事がなかったので念の為記載します。 import { initializeApp } from 'firebase/app' import { getFirestore } from 'firebase/firestore' const firebaseConfig = { // Firestore上で取得できる固有のconfig値 } initializeApp(firebaseConfig) const db = getFirestore() サブコレクションを全て取得する import { collection, getDocs } from 'firebase/firestore' const uid = 'user1' // user1 というIDを持ったユーザであると仮定します。 // 'users'というコレクションの中のユーザ一人を'user1'というIDで一意に特定します。 = ドキュメント // 'user1'というドキュメントの中の'blogs'というコレクションを全て取得。 const snapShots = await getDocs(collection(db, 'users', uid, 'blogs')) snapShots.forEach((s) => { // なんらかの処理 }) サブコレクションの中をさらに一意に特定する import { doc, getDoc } from 'firebase/firestore' const uid = 'user1' const blogId = 'blog1' // 'blog1'というIDを持ったブログが1つあると仮定します。 // 取得したサブコレクションから、更に'blogId'で一意に特定する const blog = await getDoc(doc(db, 'users', uid, 'blogs', blogId)) const blogData = blog.data() サブコレクションをソートして取得する import { collection, getDocs, orderBy, query } from 'firebase/firestore' const uid = 'user1' // queryとorderByを使って、ブログの日付の新しい順で並び替えます。 const q = query( collection(db, 'users', uid, 'blogs'), orderBy('date', 'desc') // これ以降にさらにorderByで並び替え条件を追加することも可能。 ) const snapShots = await getDocs(q) snapShots.forEach((s) => { // なんらかの処理 }) まとめ 1. コレクションを取得するときはgetDoc s (docの複数形です!)とcollectionを使う 2. ドキュメントを取得する時はgetDocとdocを使う 3. コレクション名の指定 → IDを指定 → サブコレクション名の指定 → IDを指定... の順番で、どんな深いサブコレクションでもコレクション自体やドキュメントを指定できます。 以上です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Nuxt.js】axiosを使った非同期通信

はじめに こんにちは。 こちらの記事では、axiosで非同期通信を行う方法を記しています。 誤っている点がございましたらコメントいただけると幸いです。 axiosとは axiosとはブラウザやnode.js上で動くPromiseベースのHTTPクライアントで、HTTP通信を行いたいときに使うと簡単に実装できるようになる。Nuxt.jsに限らず、JavaScriptで使えるライブラリです。 実装のゴール 非同期通信で受け取ったデータのIDとユーザー名を表示させる。 axiosをインストールする Nuxtで新規プロジェクトの作成する際や個別でインストールできる。 axiosのインストールがされていると、package.jsonのdependenciesのところにバージョンが表示される。 APIからデータを取得する 今回はJSONPlaceholderのusersデータを使用する。 script <script> const axios = require('axios') // import axios from 'axios';  でも定義できる。 const url = 'https://jsonplaceholder.typicode.com/users' export default { asyncData({ params }){ return axios.get(url) .then((res) => { return { users: res.data } }) } } </script> axiosをいつでも使える状態に定義しておき、URLも変数に入れておく。 asyncDataは、コンポーネントをロードする前に非同期の処理を行えるNuxt.jsのメソッドです。 axios.getでAPIのデータを取得し、resにサーバーからのデータが格納される。usersと名前をつけることで呼び出しやすくしておく。 template <template> <div> {{ users[0] }} </div> </template> axiosで受け取ったAPIのデータを、マスタッシュ構文で1件分表示する。 async, awaitで置き換える axiosはPromiseベースのHTTPクライアントなので、先ほどのscriptの記述をasync, awaitで書き換えることができる。 script <script> const axios = require('axios') const url = 'https://jsonplaceholder.typicode.com/users' export default { async asyncData({ params }){ const res = await axios.get(url) return { users: res.data } } } </script> 先ほどと同じ処理結果が得られる。 IDとユーザー名を表示 IDとユーザー名を表示を表示させるために、template側の記述を書き換える。 template <template> <div> {{ users[0].id }}:{{ users[0].name }} </div> </template> このように表示されれば完了です。 おわりに ここまでaxiosを使った非同期通信についてまとめました。 非同期については完全な理解がまだできていないので、引き続き復習を進めていきます! 以上、最後まで読んでいただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者がQiitaに人気投稿時間があるか調べてみた

はじめに JavaScript初挑戦! APIで色々できると聞いているけれども、何から挑戦してみたら良いのか分からないため、紹介してもらったQiita APIにチャレンジ。 まず初めに、一番人気のタグをつけている方々はどの位の時間に記事を投稿しているかAPIを使って調査してみたいと思います。 Qiita投稿者の投稿時間はたして・・・ 目次 使用した環境 データを取得してみる 情報を取るための下準備 一番使用されているタグを調べてみよう! 記事の投稿時間を調べてみよう! 結果 時間との関係 曜日との関係 時間と曜日の関係 最後に 使用した環境 Visual Studio Code JavaScript Qiita API データを取得してみる 調査するにあたって、必要な情報はこちらの二つ。  ・一番使用されているタグ  ・記事の投稿時間 情報を取るための下準備 「axios」というHTTP通信を簡単に行えるようにするパッケージをインストールしました。 ターミナルでこのコマンドを叩くとインストールされます。 npm i axios これで下準備完了! 一番使用されているタグを調べてみよう! この記述で使用されている記事数が一番多いタグを調べられました。 タグ一覧を作成日時の降順で返す async function main() { //ランキング一位のタグを検索 let response = await axios.get("https://qiita.com/api/v2/tags?page=1&per_page=20&sort=count"); let tag=response.data[0].id; console.log(tag); } main(); 何が出るかな、何が出るかな・・・ Python 2021/10/14現在、Pythonが一番使用されているタグでした! 記事の投稿時間を調べてみよう! 人気のタグが分かったところで、そのタグを使った記事の投稿時間を調べます。 投稿時間を調べる記述はこちら↓↓↓ 記事の一覧を作成日時の降順で返す let response2=await axios.get("https://qiita.com/api/v2/items?page=1&per_page=20&query=tag%3A"+tag); for(i=0;i<=10;i++){ console.log(response2.data[i].created_at); } 結果は・・・ 2021-10-14T14:31:36+09:00 2021-10-14T14:25:56+09:00 2021-10-14T13:46:17+09:00 2021-10-14T13:35:15+09:00 2021-10-14T12:20:18+09:00 2021-10-14T11:22:24+09:00 2021-10-14T11:20:19+09:00 2021-10-14T09:36:53+09:00 2021-10-14T09:10:22+09:00 2021-10-14T08:34:47+09:00 2021-10-14T05:21:38+09:00 取得できた! ・・・が、ここでトラブル発生 ある程度のデータが欲しいので実行回数を増やしたところ、Qiita APIの1時間あたりの実行回数を即オーバーしてしまい、エラーが発生しました。 <参考:QiitaDeveloper> 利用制限 認証している状態ではユーザごとに1時間に1000回まで、認証していない状態ではIPアドレスごとに1時間に60回までリクエストを受け付けます。 認証をしていれば、1時間に1000回まで可能になるため、こちらの記事を参考に認証キーを取得&設定し、無事解決です! よそ様の情報を簡単に参照できるWEBAPIが本当に簡単なのか体験してみた。 そして、完成したプログラムがこちら↓↓↓ const axios = require("axios"); async function main() { //ランキング一位のタグを検索 let response = await axios.get("https://qiita.com/api/v2/tags?page=1&per_page=20&sort=count", { headers: { 'Authorization': `Bearer ****************************************` } }) let tag=response.data[0].id; console.log(tag); //タグ内の記事の投稿時間を調査 for(a=1;a<=50;a++){ let response2=await axios.get("https://qiita.com/api/v2/items?page="+a+"&per_page=20&query=tag%3A"+tag, { headers: { 'Authorization': `Bearer ****************************************` } }) for(i=0;i<=10;i++){ console.log(response2.data[i].created_at); } } } main(); 理想は実行結果をファイル書き出したかったのですが、技術が足りずターミナルに表示される結果をExcelにコピペする形で決着です。 ターミナルに表示されるデータ量の関係で100ページを50ページずつに分割して実行しました。 結果 実行結果をExcelにコピペし、3つの観点でグラフを作成しました。 時間との関係 ・日中はビジネスタイムにも多く投稿 ・12時台~13時台と19時台は、前後の時間帯から大きく減少 <考察> 学校や仕事が終わる17時頃から夜にかけて投稿が増えることを予想していましたが、大きな増加がなくどの時間帯でも安定した投稿がありました。 ということは、Qiitaは学生や社会人以外にも幅広い層からの投稿がありそうです。 また、12時台~13時台、19時台の投稿が減少しているのは、食事や移動をしている人が多い時間帯と重なっている影響が考えられました。 曜日との関係 ・日曜と月曜の投稿が多い <考察> 土日の投稿が一番多いと想定していたので、結果に驚きました。 どの曜日も大きな差がないため、やはり幅広い層が投稿しているようです。 時間と曜日の関係 ・どの曜日も大きい差はないが、月曜と土曜・日曜は他の曜日よりも午前中の件数が多い <考察> 時間と曜日を比較しても、はっきりとした特徴はなかったが、土日月の動きが似ていたため、この3日間のいずれかで休日を取る人が多いと考えられました。 最後に 投稿時間を分析してみて、人間の活動時間帯は満遍なく投稿されている事が分かりました。 Qiitaで検索すると疑問がほぼ解決するのは、様々な環境にいる人が投稿し、知識が集まっているからなんだな、と分かりました。 今回は人気のタグの中から調査しましたが、対象や観点を追加したら、また違った結果が出そうなので、スキルアップした時にまたチャレンジしたいと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsにおける同期/非同期処理に関して

Node.jsの同期/非同期処理に関してのアウトプットするために本記事を投稿します。 マルチスレッド スレッドとはCPU利用の単位です。 CPUとは、Central Processing Unit(中央演算処理装置)の略で、プログラムの命令を解釈して、コンピューター全体の動作を制御する制御装置や演算を行う演算装置などの機能を持つ装置です。 近年のCPUでは、1つのプロセッサ・パッケージ内に複数のプロセッサ・コアを搭載するマルチコアプロセッサを使用しており、それに応じて複数のスレッドを同時に処理できるようになっています。(マルチスレッド) マルチスレッドを利用するとサーバーは複数のリクエストを受け取った際に、スレッドを増やして対応します。 しかし、リクエストが大量に届いた際にスレッドが多くなりすぎて、メモリの消費量が多くなったり、効率が悪くなるC10K問題(クライアント1万台問題)のような現象が起きる可能性があります。 Node.jsが採用しているシングルスレッドは、C10K問題を解消するのに有効です。 シングルスレッド 前章でも記載しましたが、Node.jsはシングルスレッドを採用しています。 シングルスレットとは、マルチスレッドと反対で1つのスレッドのみで処理を実行します。 シングルスレッドのメリット ・スレッドが1つであるため、C10K問題を解決できる シングルスレッドのデメリット ・スレッドが1つであるため、時間のかかる処理がある場合に、次の処理の待ち時間が増えてパフォーマンスが下がる可能性がある Node.jsでは、非同期 I/Oを用いてシングルスレッドのデメリットを解消します。 非同期I/O I/Oとは入出力処理入出力のことを指します。 非同期 I/Oでは、主にノンブロッキングI/Oを使用して非同期に処理をします。 例えば、時間のかかるAという処理の後にBという処理を実行するとします。 同期I/Oの場合は、Aの処理が終了した後に、Bの処理を実行します。 非同期I/Oでは、時間のかかる処理Aが終了する前に処理Bを実行して、時間を短縮することができます。 時間軸で処理を分散させて、1つのスレッドでも高速に処理を実行することができます。 ブロッキングとノンブロッキング ブロッキング ブロッキングとは、1つの処理が終了するまで、他の処理を実行しないことです。 「fs」というNodeパッケージの 「readFileSyncメソッド」などです。 ノンブロッキング ノンブロッキングとは、ブロッキングを行わず、非同期に処理を実行することです。 「fs」というNodeパッケージの 「readFileメソッド」などです。 具体例 「readFileSync」メソッドは、ファイルを読み込むブロッキングメソッドであり、同期I/Oを実現します。 「readFile」メソッドは、ファイルを読み込むノンブロッキングメソッドであり、非同期I/O実現します。 fs.readFileSync('./te.txt'); // ファイルが読み込まれるまでここでブロック console.log("ブロッキングメソッド") fs.readFile('./te.txt', (err, data) => { console.log("readFileメソッドを使用してファイルの読み込みが完了") }); console.log("ノンブロッキングメソッド") // 出力結果 ブロッキングメソッド ノンブロッキングメソッド readFileメソッドを使用してファイルの読み込みが完了 readFileSyncメソッドはブロッキングメソッドであるため、テキストファイルを読み込む処理が終了するまで、次の処理は実行されません。 readFileメソッドは、ノンロッキングメソッドであるため、非同期に次の処理が実行されています。 Node.jsでは、基本的に非同期I/Oを用いて処理を実行し、必要に応じてブロッキングメソッドやコールバック関数/Promise/async/awaitなどを使用して柔軟に同期/非同期処理を実行することができます。 awaitはブロッキングをしているのか function a(){ fs.readFileSync('./te.txt'); // ファイルが読み込まれるまでここでブロック console.log("ブロッキングメソッド") } async function b(){ return new Promise(function(resolve){ fs.readFile('./te.txt', (err, data) => { console.log("readFileメソッドを使用してファイルの読み込みが完了") resolve() }) console.log("readFileより先に処理されます") }); } (async ()=>{ a() await b() console.log("readFileより後に処理されます") })(); // 出力結果 ブロッキングメソッド readFileより先に処理されます readFileメソッドを使用してファイルの読み込みが完了 readFileより後に処理されます 上記のコードを作成してawaitがブロッキングを実行しているかを確認しました。 一見同期処理の様に見受けられますが、awaitはブロッキングをしているわけではありません。 以下、参考文献に記載しているページから参照しています。 await 式は返されたプロミスが履行されるか拒否されるまで実行を中断することで、プロミスを返す関数をあたかも同期しているかのように動作させます。 上記により、awaitは同期のような処理に見えますが、ブロッキングはしていないことがわかります。 参考文献 Node.js公式 https://nodejs.org/ja/about/ awaitに関して https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JS】相対パスを正規表現でディレクトリ部分とファイル名部分に分ける

正規表現を使ってディレクトリとファイル名に分ける おれおれ、かんたん忘備録。 基本 script.js const path = '/acchi/kocchi/socchi/test.html'; const dir = path.replace(/[^/]*$/, ''); // '/acchi/kocchi/socchi/' const file = path.replace(/.*\//, ''); // 'test.html' replace(/[^/]*$/, '') と replace(/.*\//, '') が味噌です。 応用 ある特定のディレクトリ内の*test.htmlを全てignoreしたい!ってときに、 ファイルを比較するのに使える。使った。もっといい書き方、あるかも。 対象: - /acchi/kocchi/socchi/*test.html - /acchi/kocchi/socchi/test.html script.js const targetPathList = [ '/acchi/kocchi/socchi/test.html', '/acchi/kocchi/socchi/_test.html', '/acchi/kocchi/socchi/OLDtest.html', ]; const ignorePathList = [ '/acchi/kocchi/socchi/test.html', '/acchi/socchi/test.html', // 増やしていってもok ]; for (let i = 0; i < targetPathList.length; i++) { const target_dir = targetPathList[i].replace(/[^/]*$/, ''); const target_file = targetPathList[i].replace(/.*\//, ''); let flag = false; for (let j = 0; j < ignorePathList.length; j++) { const ignore_dir = ignorePathList[j].replace(/[^/]*$/, ''); const ignore_file = ignorePathList[j].replace(/.*\//, ''); const file_regex = new RegExp(ignore_file + '$'); // = test.html$ const dir_check = (ignore_dir == target_dir); const file_check = target_file.match(file_regex); if(dir_check && file_check) { flag = true; break; } } if(flag) { console.log(targetPathList[i] + 'は、ignore対象ファイルです。'); // ~~~~~ 以下に任意の記述 ~~~~~ } } 背景 バックエンドPythonとフロントエンドJSを使って、JSベースの自作FTPソフトを作っているときに FTP対象外ファイルを特定の条件ではじきたかったので上記に至った。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GASで動的ページのスクレイピング

忘れないようにする自分用のメモ はじめに GASでは静的ページのスクレイピングは簡単にできるが、動的ページのスクレイピングに躓いたのでメモ 静的ページではUrlFetchApp.fetchですぐに取得できる 動的ページだとエラーが出るか、中身が無いhtmlだけ取ってくる ので 外部に頼るしかない 使うもの GAS, Parser, PhantomJsCloud, スクレイピングをする動的ページ(今回はReality) テスト用にRealityで活動されているこまいぬさんのフォロワー数を取得してみる (https://reality.app/profile/232c82a5) やってみる ・まずGASでParserを入れる ツール -> スクリプトエディタでライブラリを選んだら スクリプトIDを入れる スクリプトID 1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw ・PhantomJsCloudに登録してAPIKeyをもらう PhantomJsCloud.com ココに書いてある ・その後コードを書く forReality.gs function getRealityFollower() { var today = Utilities.formatDate(new Date(), "JST","yyyy/MM/dd"); var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); var sheet = spreadsheet.getSheetByName("TEST"); //スプレッドシートの指定 var lastRow = sheet.getLastRow(); var row = lastRow + 1; var URL = "https://reality.app/profile/232c82a5"; var key = "APIKEY"; //もらったAPIKeyをここにいれる var payload = { url:URL, renderType:"HTML", outputAsJson:true}; payload = JSON.stringify(payload); payload = encodeURIComponent(payload); var url = 'https://phantomjscloud.com/api/browser/v2/'+ key + '/?request=' + payload; var response = UrlFetchApp.fetch(url); var json = JSON.parse(response.getContentText()); var source = json["content"]["data"]; var follower = Parser.data(source).from('<span class="profile__followlist--Number">').to('</span>').iterate(); sheet.getRange(row, 1).setValue(today); sheet.getRange(row, 2).setValue(follower[1]); var diff = follower[1] - sheet.getRange(lastRow,2).getValue() ; sheet.getRange(row, 3).setValue(diff); } 保存したらトリガー -> トリガーを追加で関数を選ぶ 今回はgetRealityFollowerを選択 そしてイベントを時間主導型にして日付ベースのタイマーを選択する 時刻は午前0時~1時とした これで24時間に1回、午前0時~1時の間に実行される あとは保存して終了 さくっと取得できるようにしたら適当に体裁を整えて入力されるようにする 最終的にこんな感じになった もう少し凝ってもいいかなと思うが個人で使う分には問題ないと思う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

指数バックオフ + ジッターをTypeScriptでやるだけ

導入 外部API叩く系のコード、テストで通ってもスケーリングしたら死ぬことがあります 単純に一回に大量に叩いたり、そうでなくてもエラーから復旧したりした時に全員が同期して叩くみたいなことがあると、それはもはやDDoS攻撃だからです それを解決するのが指数バックオフです ミスったらいい感じに待ってやり直すというアルゴリズムです その待つ時間まで一緒だと同期攻撃が繰り返されるだけなので乱数でずらします それがジッターです GCPのCloudStorageのドキュメントとかでも自分で実装しろと書いてあります 悲しい 本質 このアルゴリズムの本質は待ち時間です expBackoff.ts const MIN_OFFSET_MSEC = 2000 await sleep( (2 ** retries) * MIN_OFFSET_MSEC * ( 1 + Math.random() ) ) 今回は1回目は2〜4秒、2回目は4〜8秒、3回目は8〜16秒....の中で一様分布にしています 冪乗具合やrandom具合はお好みでアレンジしてください コード 関数と最大リトライ数を引数に、指数バックオフを実行する関数です expBackoff.ts const MIN_OFFSET_MSEC = 2000 // 最初は2秒からスタート、それ以降は倍倍で増える export const expBackOff = async (func: Function, MAX_RETRIES: number) => { let retries = 0 // やり直した回数 let retry = true // やり直すかフラグ let res while(retry && retries < MAX_RETRIES){ await sleep( (2 ** retries) * MIN_OFFSET_MSEC * ( 1 + Math.random() ) ) // 本質 try { res = await func() // undefinedは返さないで retry = false } catch (e) { console.log("retryCount: ", retries + 1) console.log("expbackoff ERROR: ", e) } retries += 1 } if(res == undefined) { throw new Error("Expbackoff failed. retryCount: " + retries) } return res } async function sleep(msec: number) { return new Promise(function(resolve) { setTimeout(function() {resolve()}, msec); }) } 使い方 index.ts const fetch = require('node-fetch'); const fetchFunc = async () => { // 指数バックオフさせたい関数を作る return await fetch(URL, options).then((response: any) => { // ちゃんとパースしてエラーに昇華させる if(isYokunai(response)){ // レスポンスがよくなかった時 throw new Error(response) } else { return response } }) // return await someGoodApi() // ちゃんとエラーハンドリングされるならこれだけでもよい } const response = await expBackOff(fetchFunc, 5).then((res: any) => { // 5回やり直す console.log("RESULT: ", res) return res }).catch((e) => { console.log("ERROR: ", e) return new Error(e) // 好きにハンドリングしてください }) まとめ 良いスケーリングライフを!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ウェブページは作れませんでした 【RESTART】

ウェブページは作れませんでした(結論) 「progate」にて学習すること約1か月 「Web開発パス(Node.js)」を一通りこなしてみて とりあえず何かウェブページ作ってみるかと思った 結論、どうやって作ればいいのか解らず… 学習プロセスの見直し 「progate」だけ行ってしまうと自分の場合は インプットのみになってしまい、定着しないと反省 そこで以下のようなプロセスの仮説を立てて実行することにした 学習プロセスのフェーズ詳細 フェーズ1_学習 これまでと同じように「progate」のカリキュラムをこなすフェーズ フェーズ2_記録 「progate」で書いたコードをテキストファイル化して印刷、手書きで メモ等を加える(昭和生まれなのでアナログ手法) フェーズ3_実践 手書きメモを加えたテキストファイルを参考にして「Codepen」で作成する フェーズ4_発信 作成プロセスを言語化してQiitaの記事を作成する 人間は楽な方に流れる 計画を立ててプロセスを設定しないと どうしても楽なインプットだけに偏ってしまう それに気付かされた1か月だったと言える 過去記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactで作るTodoアプリ

前回JavaScriptで作ったTodoアプリをReactで作った時のメモです。 完成イメージ 実装 JSX まずはJSXで基本的なHTML部分を書いときます。 src/App.jsx import React from "react"; import "./styles.css"; export const App = () => { return ( <> <div className="input-area"> <input placeholder="TODOを入力" /> <button>追加</button> </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> <div className="list-row"> <li>ああああ</li> <button>完了</button> <button>削除</button> </div> <div className="list-row"> <li>いいいい</li> <button>完了</button> <button>削除</button> </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> <div className="list-row"> <li>いいいい</li> <button>戻る</button> </div> </ul> </div> </> ); }; Reactの実装を意識した形にする Todoの部分をstateにして初期値を設定しておきます。 src/App.jsx import React from "react"; import { useState } from "react"; // 追加 import "./styles.css"; export const App = () => { //-----------------------追加------------------------------------- const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); //--------------------------------------------------------------- return ( <> <div className="input-area"> <input placeholder="TODOを入力" /> <button>追加</button> </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> //-----------------変更------------------------ {incompleteTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>完了</button> <button>削除</button> </div> ); })} //---------------------------------------------- </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> //-----------------変更------------------------ {completeTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>戻る</button> </div> ); })} //---------------------------------------------- </div> </ul> </div> </> ); }; 解説 stateとして定義したincompleteTodosとcompleteTodosをmapを使ってループしています。 mapなどを使用するときはkeyの設定を忘れずに! Todo追加 src/App.jsx import React from "react"; import { useState } from "react"; import "./styles.css"; export const App = () => { const [todoText, setTodoText] = useState(""); //追加 const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); //-----------------------追加-------------------------------- const onChangeTodoText = (e) => setTodoText(e.target.value); const onClickAdd = () => { if (todoText == "") return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(""); }; //------------------------------------------------------------ return ( <> <div className="input-area"> //-----------------変更---------------------- <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> //------------------------------------------ </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> {incompleteTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>完了</button> <button>削除</button> </div> ); })} </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> {completeTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>戻る</button> </div> ); })} </div> </ul> </div> </> ); }; 解説 Reactでinput部分はvalueにstateを持たせinputにonChangeイベントを使い以下のような関数を書くのは定番。 const onChangeTodoText = (e) => setTodoText(e.target.value); 追加ボタンにonClickイベントでTodoを追加する関数(onClickAdd)を定義してスプレッド構文を使うことで追加している。 if (todoText == "") return;この部分は空文字の場合はreturnすることで空文字投稿を防いでいる。 Todo削除 src/App.jsx import React from "react"; import { useState } from "react"; import "./styles.css"; export const App = () => { const [todoText, setTodoText] = useState(""); const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); const onChangeTodoText = (e) => setTodoText(e.target.value); const onClickAdd = () => { if (todoText == "") return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(""); }; //---------------追加------------------------ const onClickDelete = (index) => { const newTodos = [...incompleteTodos]; newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; //------------------------------------------ return ( <> <div className="input-area"> <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> {incompleteTodos.map((todo,index) => { //追加 return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> //追加 </div> ); })} </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> {completeTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>戻る</button> </div> ); })} </div> </ul> </div> </> ); }; 解説 削除ボタンにonClickイベントでonClickDelete関数を定義。mapと関数の引数にindexを渡すことで何番目のTodoの削除ボタンが押されたかどうかを判定できる。(関数に引数を渡すときはアロー関数を使う) spliceを使って削除している。 Todo完了 src/App.jsx import React from "react"; import { useState } from "react"; import "./styles.css"; export const App = () => { const [todoText, setTodoText] = useState(""); const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); const onChangeTodoText = (e) => setTodoText(e.target.value); const onClickAdd = () => { if (todoText == "") return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(""); }; const newTodos = [...incompleteTodos]; newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; //-------------------------追加----------------------------------------- const onClickComplete = (index) => { const newIncompleteTodos = [...incompleteTodos]; newIncompleteTodos.splice(index, 1); const newCompleteTodos = [...completeTodos, incompleteTodos[index]]; setIncompleteTodos(newIncompleteTodos); setCompleteTodos(newCompleteTodos); }; //-------------------------------------------------------------------- return ( <> <div className="input-area"> <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> {incompleteTodos.map((todo,index) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button onClick={() => onClickComplete(index)}>完了</button> //追加 <button onClick={() => onClickDelete(index)}>削除</button> </div> ); })} </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> {completeTodos.map((todo) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button>戻る</button> </div> ); })} </div> </ul> </div> </> ); }; Todo戻す src/App.jsx import React from "react"; import { useState } from "react"; import "./styles.css"; export const App = () => { const [todoText, setTodoText] = useState(""); const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); const onChangeTodoText = (e) => setTodoText(e.target.value); const onClickAdd = () => { if (todoText == "") return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(""); }; const newTodos = [...incompleteTodos]; newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; const onClickComplete = (index) => { const newIncompleteTodos = [...incompleteTodos]; newIncompleteTodos.splice(index, 1); const newCompleteTodos = [...completeTodos, incompleteTodos[index]]; setIncompleteTodos(newIncompleteTodos); setCompleteTodos(newCompleteTodos); }; //-------------------------追加----------------------------------------- const onClickBack = (index) => { const newCompleteTodos = [...completeTodos]; newCompleteTodos.splice(index, 1); const newIncompleteTodos = [...incompleteTodos, completeTodos[index]]; setCompleteTodos(newCompleteTodos); setIncompleteTodos(newIncompleteTodos); }; //-------------------------------------------------------------------- return ( <> <div className="input-area"> <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> {incompleteTodos.map((todo,index) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </div> ); })} </div> </ul> </div> <div className="complete-area"> <p className="title">完了のTODO</p> <ul> {completeTodos.map((todo, index) => { //追加 return ( <div key={todo} className="list-row"> <li>{todo}</li> <button onClick={() => onClickBack(index)}>戻る</button> // 追加 </div> ); })} </div> </ul> </div> </> ); }; 解説 完了の処理は 未完了リストから削除 → 完了リストに追加 戻るの処理はその逆なので今までの追加と削除の処理を組み合わせることで実装できる。 コンポーネント分割 最後にコンポーネント分割して完成。 JSX src/App.jsx import React from "react"; import { useState } from "react"; import "./styles.css"; export const App = () => { const [todoText, setTodoText] = useState(""); const [incompleteTodos, setIncompleteTodos] = useState([ "ああああ", "いいいい" ]); const [completeTodos, setCompleteTodos] = useState(["うううう"]); const onChangeTodoText = (e) => setTodoText(e.target.value); const onClickAdd = () => { if (todoText == "") return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(""); }; const newTodos = [...incompleteTodos]; newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; const onClickComplete = (index) => { const newIncompleteTodos = [...incompleteTodos]; newIncompleteTodos.splice(index, 1); const newCompleteTodos = [...completeTodos, incompleteTodos[index]]; setIncompleteTodos(newIncompleteTodos); setCompleteTodos(newCompleteTodos); }; const onClickBack = (index) => { const newCompleteTodos = [...completeTodos]; newCompleteTodos.splice(index, 1); const newIncompleteTodos = [...incompleteTodos, completeTodos[index]]; setCompleteTodos(newCompleteTodos); setIncompleteTodos(newIncompleteTodos); }; return ( <> //-----------------------------変更------------------------------------------ <InputTodo todoText={todoText} onChange={onChangeTodoText} onClick={onClickAdd} /> <IncompleteTodos todos={incompleteTodos} onClickComplete={onClickComplete} onClickDelete={onClickDelete} /> <CompleteTodos completeTodos={completeTodos} onClickBack={onClickBack} /> //------------------------------------------------------------------------- </> ); }; 完了リスト src/components/CompleteTodos.jsx import React from "react"; export const CompleteTodos = (props) => { const { completeTodos, onClickBack } = props; return ( <div className="complete-area"> <p className="title">完了のTODO</p> <ul> {completeTodos.map((todo, index) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button onClick={() => onClickBack(index)}>戻る</button> </div> ); })} </ul> </div> ); }; 未完了リスト src/components/IncompleteTodos.jsx import React from "react"; export const IncompleteTodos = (props) => { const { todos, onClickComplete, onClickDelete } = props; return ( <div className="incomplete-area"> <p className="title">未完了のTODO</p> <ul> {todos.map((todo, index) => { return ( <div key={todo} className="list-row"> <li>{todo}</li> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </div> ); })} </ul> </div> ); }; Input src/components/InputTodo.jsx import React from "react"; export const InputTodo = (props) => { const { todoText, onChange, onClick } = props; return ( <div className="input-area"> <input placeholder="TODOを入力" value={todoText} onChange={onChange} /> <button onClick={onClick}>追加</button> </div> ); }; 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】bladeファイルでReact側に変数を渡す

はじめに Laravelで一部分をReactでSPA化した際、APIを使うまでもなさそうな変数をグローバル変数として渡していました。 一応、備忘録として残します。 実装 script内でconst access_token = "{{ $access_token }}"のように値を渡します。 @section('main') <link href="{{ asset('/css/app.css') }}" rel="stylesheet" type="text/css"> <script> const access_token = "{{ $access_token }}" const api_url = "{{ url('/graphql') }}"; const app_store_url = "{{ env('APP_STORE_URL') }}" const pet_age = @json(config('define.pet.age')); </script> <div id="app"></div> <script src="{{asset('/js/app.js')}}"></script> @stop 以下のような連想配列(および配列)を渡す際には、@jsonでJSONに変換して渡します。 pet.php <?php return [ 'age' => [ 'dog' => 5, 'cat' => 10, 'bird' => 8, ] ]; React側で変数を呼び出す際、TypeScriptを使っているとWarningCan't find name ~がでるので、新しく変数を用意して// @ts-ignoreをつけてあげます。 index.ts const Component = () => { // @ts-ignore const petAge = pet_age ... } 参考資料
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

face-api.jsの値を安定させるため、取得し続ける連続データの平均値を出した

face-apiで取得した値が安定しない。 いま表情で動かすゲームをつくっていて、 face-api.jsを使って、表情データを取得するようにしているのですが、 ランドマークの値ってなかなか安定しないんですよね。 じゃあ、どうするかと考えて、 取得した連続10個のデータの平均値を出すことで、 ある程度安定させてみました。 連続した10個のデータの平均値を出す 10個のデータは常に更新されていくので、 引数を配列にしてました。 function getAverage(array){ let total = 0; let average = 0; for (let i = 0 ; i < array.length ; ++i) { total += array[i]; average = total / array.length; } return average; } ここまでが平均を出す関数。 let array = [0 , 0]; function render() { faceapi.detectSingleFace( video, options ).withFaceLandmarks() .then((result) => { let mouseDistance = Math.abs(result.landmarks.positions[63].y - result.landmarks.positions[67].y); array.push(mouseDistance); if (array.length > 10) { array.shift(); //10件を超えたら配列の先頭の値を削除 } console.log(array); let average = getAverage(array); console.log(average); そして、こちらが顔のランドマークから取得した 最新10個の連続データの平均値を出すまでのところです。 配列の最後尾にどんどん値を追加していきつつ、 11個目のデータは古いものから削除していくようにしました。 これでできました。 自分の備忘録として プログラミングを学んでもすぐに忘れてしまうので、 自分の備忘録としても残しておきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【改】初心者向けの記事って多すぎん??(javascript初心者向けQiitaAPIでLGTM数TOP10を出してみる)

「初心者」と「初心者向け」って違うよね 初投稿記事にありがたいコメントをいただきました。 以下コメントの引用です。 初心者: 初心者が書いた記事、あやふやで正しくない内容も多い(車の初心者マークと同じ) 初心者向け: 先輩が初心者向けに書いた記事 た、確かに……! 初心者が書いた記事と、初心者向けに書かれた記事では違いすぎる……! 日曜大工と宮大工くらい違う……!!(それは違う) と、いうことで検索に使う単語を「初心者」から「初心者向け」に変えて再度TOP10を出してみます。 概要 記事タイトル、本文、タグのいずれかに「javascript」「初心者向け」の2単語が含まれている記事を抽出。 2021年9月までの記事を取得する。 LGTM数で降順化しTOP10の記事を出す。 サンプルコード homework.js const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { for (page = 1;page<=100;page++){ let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者向け") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer a57b66c2c1c2a8a9bb53be4879f6ecf5ab28c5a4" } }); //取得したデータ件数分タイトル、URL、LGTM数取得 for (let i = 0; i < response.data.length; i++) { var title_name = response["data"][i]["title"]; var sample = response["data"][i]["url"]; var cntlike = response["data"][i]["likes_count"]; console.log(title_name+"¥"+sample+"¥"+cntlike); } } } main(); javascript初心者向けLGTM数TOP10(~2021年9月作成記事) 検索単語を「javascript」「初心者向け」にしました No 記事タイトル LGTM数 1 AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ 6251 2 イマドキのJavaScriptの書き方2018 5554 3 良いコードの書き方 4364 4 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 3163 5 初心者プログラマが犯しがちな過ち25選 2492 6 【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法 2444 7 すべての開発者へ。すごいGitHubリポジトリ10選 2374 8 2018年のフロントエンドエンジニアならこの程度は知ってて当然だよな? 2106 9 Python Webスクレイピング テクニック集「取得できない値は無い」JavaScript対応@追記あり6/12 1959 10 新人にドヤ顔で説明できるか、今風フロントエンド開発ハンズオン(Git/Node.js/ES6/webpack4/Babel7) 1948 ちなみに検索語「javascript」「初心者」でだしたTOP10はこちら。 No 記事タイトル LGTM数 1 AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ 6248 2 イマドキのJavaScriptの書き方2018 5554 3 良いコードの書き方 4363 4 すべての新米フロントエンドエンジニアに読んでほしい50の資料 3876 5 2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ 3647 6 プログラミング勉強を加速させる7つの習慣 3379 7 トップデベロッパーになるために作成したいアプリ8選 3248 8 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 3163 9 初心者プログラマが犯しがちな過ち25選 2492 10 【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法 2444 ちょっと変わった TOP3は不動でしたが、4位以降は変化がありました。 改めて出したTOP10の方がより初心者向けになったかもしれません。 コードは出来上がっていたので検索単語を変えただけの楽チン作業ですみました♪ 相変わらず手作業ではありましたが……。 おまけ記事としてあげておきます。 コメントくださった方ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript活用】QiitaAPIを活用してバイク好きがいるか調べてみた

目次 はじめに 背景・目的 環境、言語等 処理コードおよび処理結果 1.各種定数の定義と値の代入 2.[bike]と[バイク]のタグを含む記事数取得 3.[bike]と[バイク]のキーワードが含まれている記事の一覧化 4.[bike]と[バイク]タグのフォロー人数取得 結果、考察 さいごに 記事の書き方で参考にしたURL はじめに バイクが好き。Harley-Davidsonが好き。なんならその中でもスポーツスターが好き。 愛車はHarley-Davidson XL883R 2007年モデル。白いボディに一目惚れ! 社会人として13年間事務部門で育ってきた30代が人事異動をきっかけにSE目指してスタートを切りました!(Microsoft製品(Access、Excel)を使ったEUCツールの開発経験あり。) 背景・目的 QiitaAPI、JavaScripttを習得するにあたり、バイク好きがどれくらいいるかを調べることにしました。 Qiitaの中にバイク関連の記事(タグ、キーワード)はあるのか?バイクをフォローしているバイク好きな人はどれくらいいるのか?以下【検索するタグおよびキーワード】で【処理】を実行することにします。 【検索するタグおよびキーワード】  ・bike  ・バイク 【処理】  ・タグが設定された記事数をそれぞれ取得  ・キーワードが含まれた記事のタイトルとURLをそれぞれ10件ずつ一覧化  ・タグのフォロワー数をそれぞれ取得 環境、言語等 ・Visual Studio Code ・Qiita API ・JavaScript ・Node.js 処理コードおよび処理結果 1.各種定数の定義と値の代入 キーワードなど色々なところで使用するので、定数(変数)を定義します。(今回は定数のみ使用) 一か所変えればすべて変わる!定数(変数)はとても便利です。 今回は[bike][バイク]の二種類のキーワードを使うことにします。 [バイク]は日本語のため、エンコード処理をする必要があります。 モジュール内でエンコードとデコードの切り替え方法が解決できなかったので、最初からエンコードして代入することにします。 ★参考:JavaScriptにおける変数と定数について ★参考:encodeURIComponentが世界基準だと誤解してた話 const axios = require('axios'); const accessT = '自分のアクセストークンを指定' const NameEnglish = 'bike' const NameJapan = 'バイク' const NameJapanEn = encodeURIComponent('バイク') 2.[bike]と[バイク]のタグを含む記事数取得 [bike]と[バイク]のタグを含む記事数をそれぞれ取得します。 「1.各種定数の定義と値の代入」で設定した定数を使用します。 ★参考:初心者がQiitaのAPIにアクセスして、初心者についてのタグを考察してみた(その①) 処理コード //関数mainを定義 ★[bike][バイク]タグを含む記事の数 async function main() {  //bike let response1 = await axios.get('https://qiita.com/api/v2/tags/' + NameEnglish, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('1[' + NameEnglish + ']タグを含む記事数:'+ response1.data.items_count);  //バイク let response2 = await axios.get('https://qiita.com/api/v2/tags/' + NameJapanEn, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('2[' + NameJapan +']タグを含む記事数:'+ response2.data.items_count); } main(); 実行結果 1[bike]タグを含む記事数:3 2[バイク]タグを含む記事数:12 3.[bike]と[バイク]のキーワードが含まれている記事の一覧化 [bike]と[バイク]のキーワードが含まれている記事をタイトルとURLを取得します。 「1.各種定数の定義と値の代入」で設定した定数を使用します。 100件を取得しようと考えていましたが、出力した後にQiitaへの記載が大変だったので10件へ変更しました。 CSV等に書き出ししたかったのですが、参考に見た記事が難しかったので諦め、Qiita上に貼ると表になる形式で出力していきます。 ★参考:きのこの山 VS たけのこの里 あなたはどっち派?を調べてみた ★参考:JavaScriptとQiitaAPIで取得した人気タグ情報をplotlyで散布図表示してみる 処理コード //関数mainを定義 ★[bike][バイク]キーワードを含む記事10件分TitleとURL取得 async function main() { //bike let response1 = await axios.get('https://qiita.com/api/v2/items?per_page=10&page=1&query='+ NameEnglish, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('| [' + NameEnglish + ']キーワードを含む記事のtitle | URL |') console.log('|:-|:-|') for (let i = 0; i < response1.data.length; i++) { console.log('|' + response1.data[i].title + '|' + response1.data[i].url +'|'); } //バイク let response2 = await axios.get('https://qiita.com/api/v2/items?per_page=10&page=1&query='+ NameJapanEn, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('| [' + NameJapan + ']キーワードを含む記事のtitle | URL |') console.log('|:-|:-|') for (let i = 0; i < response2.data.length; i++) { console.log('|' + response2.data[i].title + '|' + response2.data[i].url +'|'); } } main(); 実行結果 [bike]キーワードを含む記事一覧(10件) [bike]キーワードを含む記事のtitle URL 書籍「ユースケースで学ぶDataiku-自転車シェアリングサービスの利用パターン分析-」告知 https://qiita.com/ayoyo/items/7489fc42c7127eb07d82 「自動化ツール」活用は、これからのデータ分析スキル向上の鍵だ!(と思う) https://qiita.com/hima2b4/items/73d8053574ea3e85e150 It's too late, your data has been compromised https://qiita.com/Sovai/items/70961e362491de53d2a5 [初心者向け] BootstrapのCarouselを暗くして背景として使う https://qiita.com/daisuke114/items/e91ec77bd3fec9165708 DynamoDB入門編(チュートリアル実施) https://qiita.com/kouji0705/items/7750d35eaaf2e53529c2 道路安全 自己適応システムの安全分析。安全(25) https://qiita.com/kaizen_nagoya/items/449ccda6821efeff574f 自動車安全資料を仮訳してみた。分析はこれから。安全(27) https://qiita.com/kaizen_nagoya/items/c28c707ef226e65b780e OpenStructを用いる オブジェクト指向設計実践ガイドより https://qiita.com/RyomaKaneko/items/455808398c770ede3abb モジュールを適切に使う オブジェクト指向設計実践ガイド https://qiita.com/RyomaKaneko/items/17670b8975099b039cc5 コンポジション オブジェクト指向設計実践ガイドより https://qiita.com/RyomaKaneko/items/b2733e5818285a37634a [バイク]キーワードを含む記事一覧(10件) [バイク]キーワードを含む記事のtitle URL バイクで走るタイムリミットをLINE_BotとWeb_APIを組み合わせて実装してみた~ https://qiita.com/tanakahiroki/items/e436a80d7d25a6421ca9 NODE-REDでビジュアルプログラミング辞書型チャットボット人工無能APIを作って遊ぼ https://qiita.com/iwaxse0430/items/985fc79b9305ee469731 PICと気圧センサで高度計を作成する https://qiita.com/keitanak/items/c40ea7706fd43014d2e1 AWS Cognito にトライしてみた https://qiita.com/meowmeowcats/items/212ce109254647be609d Railsポートフォリオ【Tamari-Ba】についてまとめてみた https://qiita.com/vit_udon_husqy/items/f87ca0bdb4b23f0449e9 データサイエンティストの仕事~日立のデータサイエンティストに聞いてみた!~シリーズ3~ https://qiita.com/KH_MOON/items/b8f21589547fbd21fe12 Javaマルチスレッド https://qiita.com/syouekiko/items/e8f94de918d39d34d7e2 DB設計のセオリーである正規形を自分なりにまとめてみた https://qiita.com/play-life/items/1f2a057b74207629da74 【Google Cloud Day'21】「製造業における Google Cloud を活用した全社データ利活用推進の進め方とは?」を視聴して https://qiita.com/Mune_robo/items/1be99f70b32adfa7d325 Slackにバイク川崎バイクを導入する【Python/Slackbot/Mecab】 https://qiita.com/pepperland_sk/items/ffe361b3bf3abf02ef58 処理コード //関数mainを定義 ★[bike][バイク]タグをフォローしている人の数 async function main() { //bike let response1 = await axios.get('https://qiita.com/api/v2/tags/' + NameEnglish, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('1[' + NameEnglish + ']タグのフォロワー数:'+ response1.data.followers_count);  //バイク let response2 = await axios.get('https://qiita.com/api/v2/tags/' + NameJapanEn, { headers: { 'Authorization': `Bearer ` + accessT } }); console.log('2[' + NameJapan +']タグのフォロワー数:'+ response2.data.followers_count); } main(); 実行結果 5[bike]タグのフォロワー数:1 6[バイク]タグのフォロワー数:0 結果および考察 ・バイクが好きな人は結構いる。 ・バイクに関係したツール開発などをしている記事はたくさんある。 ・タグが活用されていない。 ・タグ上限が5個までとなるとバイクを入れ込むことが難しい可能性がある。 ・キーワード検索では[bike][バイク]を含むものと指定したため自転車系の内容もヒットした。 さいごに 始めてJavaScript、Node.js、APIを実行しました。 最初から試し書きしては叩いてを繰り返しエラー連発し、直しては叩いてを繰り返したところ、1時間に60回をオーバーしました。 認証していないと1時間に60回までしか叩けないということの意味をきちんと理解していませんでした。 参考文書をもとに認証したらサクサク進みました。 ★参考:よそ様の情報を簡単に参照できるWEBAPIが本当に簡単なのか体験してみた。 利用制限 認証している状態ではユーザごとに1時間に1000回まで、認証していない状態ではIPアドレスごとに1時間に60回までリクエストを受け付けます。 ※Qiita API v2の仕様より抜粋 バイクに関係するテーマの記事を投稿している方もタグを使っていないようです。 そして、英語圏ではバイクのことは[Motorcycle]ということなので、どちらが良いのでしょうか? 投稿する際はタグを活用したいと思いましたが[bike][Motorcycle]で悩みました。 今回は[bike]タグを使いますが、適切なタグを設定できるよう頑張ります。 記事の書き方で参考にしたURL 記事名 URL Qiita記事作成方法 初心者の備忘録 https://qiita.com/U-MA/items/996ae933ae94c5711883 Qiita 記事の書き方 https://qiita.com/wdwd5454/items/7d8db521c5c0d1f570f6 Markdown記法 チートシート https://qiita.com/Qiita/items/c686397e4a0f4f11683d 良い記事を書くためのガイドライン https://help.qiita.com/ja/articles/qiita-article-guideline
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【都度更新】使ってみたいライブラリ

Githubトレンドを見て満足するだけで毎回おわっちゃうから気になったライブラリをメモしていきます。 cube.js アナリティクスの分析APIプラットフォーム バックエンド立ててデータ返すAPI等々を簡単にしてくれ、フロントでそのデータを取得し、グラフレンダリングするまでの簡単なチュートリアルもある Prisma オープンソースのORM バックエンドをNodeにするときに使ってみる vue-awesome-swiper Vue向けのWebでスワイプを簡単に実装できるライブラリ Tinderライクなアプリ作る際に便利そう
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】変数と参照の振り返り⑦ 参照とconst・引数

はじめに Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。 前回の記事 目的 変数についての理解を深める 本題 1.参照とconst // constを使った再代入 // プリミティブ値 const a = "Hello"; // constで定義した場合、再代入できない → エラーになる a = "bye"; // オブジェクト const b = { prop: "hello" } // 新しいオブジェクトを代入しようとするとエラーになる // constで変数宣言しているため、再代入不可 b = {}; // オブジェクト const b = { prop: "hello" } // プロパティに対して変更を加えようとした場合はエラーにならない b.prop = "bye"; console.log(b); // constをオブジェクトで使用した際には、 // オブジェクトの再代入はできないが、 // プロパティの変更は可能 2.参照と引数 let a = 0; // 関数の引数としてaを渡したい function fn1(arg1){ arg1 = 1; console.log(a, arg1); } // 引数aを入れて実行すると,(0,1)と出力される fn1(a); これは下記の書き方と結果が同じ let arg1 = a; arg1 = 1; console.log(a,arg1) fn1(a); プリミティブ型を関数の引数として渡す場合には 値はそれぞれ独立しているので互いに影響は受けない let b = { prop: 0 } function fn2(arg2){ arg2.prop = 1; console.log(b, arg2); } // 実行結果は{prop: 1}になる fn2(b); // つまり引数に渡したbというオブジェクトの参照が // arg2にコピーされ、bと同じオブジェクトへの実体への参照を保持しているため // プロパティの値を変更するとbの値にも影響が出る // 中でarg2にオブジェクトを渡すと function fn3(arg2){ arg2 = {}; console.log(b, arg2); } // この結果は{prop: 0} {}となる fn3(b); // この場合、bに影響は出ないがarg2だけ変更される // 値がコピーされているのか、参照がコピーされるかで結果が変わる 今日はここまで! 参考にさせて頂いた記事 【JS】ガチで学びたい人のためのJavaScriptメカニズム
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub上のJavaScriptコードをSonarCloudで検査してみる

概要 このエントリでは、GitHub上のpublicなリポジトリのJavaScriptのコードを検査するため、「SonarCloud」を使用するための方法を紹介します。SonarCloudは、SonarSource社のプロダクトの一つであり、同社がオンプレミス環境で静的検査を行うためにリリースしているプロダクトとして、SonarQubeがあります。 サービスの形態や、利用ソフトウェアのバージョンは、2021年10月時点の内容になります。 想定読者 GitHubでpublicなリポジトリを持っており、静的検査を実施してみたい方 エントリの動機 筆者が趣味のプログラムを書くにあたり、手元にSonarQubeサーバを立てずにコード検査を行いたくなりました。 SonarCloudは、(2021年10月時点では)publicなリポジトリに対する検査は無料で実施することができることも後押しになりました。 手順 SonarCloudの利用を開始する サイトのPricingのページにある、「Start Using SonarCloud」ボタンを押します。 連携先のサービスを選択します。筆者の場合は「GitHub」を選択しました。エントリ執筆時点では、このほかにBitbucket, GitLab, Azure DevOpsが選択できるようです。 連携先のいくつかの情報を使ってよいか確認されます。Authorizeボタンを押します。 自身のリポジトリを選択できるようになるので、「Analyze your first projects」に進みます。「Import an organization from GitHub」を押します。 対象とするリポジトリをすべてにするか、一部分にするかを選べます。筆者は、一つ一つ指定も手間と考え、すべてを対象としました。「Install」ボタンを押します。 SonarCloud上の"Organization"に関して、名前を決めます。Organizationには複数のユーザを参加させることができるようですが、このエントリでは筆者1名が使用する例を示しています。「Continue」ボタンを押します。 プランの選択で、このエントリでは"Free"を選択します。「Create Organization」を押します。 対象のリポジトリを選択する 対象のリポジトリを選択します。このエントリでは1つを選択し、「Set Up」を押します。 なにやらセットアップが始まり、しばし待ちます。 検査の結果を確認する 画面が遷移し、リポジトリの状況がダッシュボードで確認できます。(12Bugsって。。。) Bugが検出された場合には、数字部分をクリックすると「Issues」ページに遷移し、結果を閲覧できます。(あ、途中まで書いたけど放置してあったテストケースだ。。見つかったか。。。) 設定を加える Overviewの上部で誘導された先のページで、何をもって新しいコードとするかを定義します。このエントリでは、リポジトリの前の状態との差分としました。 Measuresのページを眺めてみる 信頼性、セキュリティ、保守性など、いくつかの観点での分析結果が参照できます。 おわりに このエントリでは、GitHubのパブリックリポジトリのJavaScriptのコードに対し、SonarCloudで静的検査をするまでを紹介しました。 Pull Request時の検査の連携については、別エントリで扱いたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Qiitaの記事の”勢い”を調べる ~もしかしたらまだ見ぬ掘り出し記事が見つかるかも~

配信者勢いランキング、5ちゃんねる勢いランキングなど、インターネットをうろうろしているとよく"勢い"という言葉を目にしますよね。 というわけでQiita記事の勢いを調べてみました。(QiitaAPIを使って) 参考になる記事をストックすることがスキルアップの近道のはず、"勢い"のある記事はきっと参考になる記事だと思うのです。 前調べ 5ちゃんねるの勢いの計算方法は次の通りだということを調べました。 勢い=レス数/(現在のunix時間-スレッド内の1番目の投稿のunix時間)÷86400 なるほど、これを参考に今回は、 ■レス数=いいねの数 ■現在の時間=現在の時間 ■1番目の投稿時間=記事の投稿時間 と定義してやってみます 結果 単月部門 集計期間:2021/9/13~2021/10/2 順位 いいね 投稿日 期間(日) 勢い URL 1 893 2021-09-29 15 61 エンジニア200人に聞いて、業務委託単価表を作りました 2 1090 2021-09-15 28 39 「あれ、プログラミングが楽しくない…」【すべてのエンジニアへ】 3 364 2021-10-03 10 35 仕事で使う技術以外はさっぱりわからないけど この先大丈夫かな……という方にオススメのLTイベントご紹介 4 41 2021-10-12 2 27 5,000円/時間以上で働く方法を考えてみた 5 226 2021-10-04 9 24 VueもReactもやったことないのでVanilla JSでやってみたSPA 6 577 2021-09-20 24 24 クリーンなReactプロジェクトの21のベストプラクティス 7 189 2021-10-05 9 22 プロダクトを作ってから登録ユーザー400名、月間売上100万円を達成するまでにエンジニアががむしゃらに行った営業方法のメモ書き 8 146 2021-10-06 7 21 過去にPLから言われた心に刻んでおきたい5つの言葉【要件定義編】 9 472 2021-09-18 25 19 【2021】モダンなPython開発環境の紹介 10 445 2021-09-19 25 18 Bash Scriptの作法 1位の記事は1日で61いいねを獲得したということになります。 この期間では突出した結果となりました。 記事を読んでみましたが、大変興味深くこの結果も納得のものでした。 続いて、期間指定なしの結果です 無差別級 集計期間:なし 順位 いいね数 投稿日 期間(日) 勢い URL 1 2537 2021-02-23 233 10.9 【2021 最新版】ノンデザイナーだからこそ知っておきたかった10のイラストサイト 2 4333 2021-05-24 507 8.5 Google社のテクニカルライティングの基礎教育資料がとても良かったので紹介したい 3 4687 2020-01-11 641 7.3 要件定義~システム設計ができる人材になれる記事 4 4363 2020-01-21 631 6.9 良いコードの書き方 5 3770 2020-03-08 584 6.5 プロジェクトリーダーというお仕事 6 2853 2020-04-16 545 5.2 VSCode に必ず入れておきたい拡張機能 7 3647 2019-11-11 702 5.2 2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ 8 9757 2016-05-16 1976 4.9 ロシアの天才ハッカーによる【新人エンジニアサバイバルガイド】 9 5435 2018-09-30 1109 4.9 VSCodeのオススメ拡張機能 24 選 (とTipsをいくつか) 10 6241 2018-03-13 1310 4.8 AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ やはり、期間が延びると勢いも衰えていく結果となっています。 しかしながら1日10いいねは単月部門でもTOP20に入る勢いで、投稿後半年以上経過している中でいまだ衰えを知らないといっても過言ではないと思います。 とりあえずすべてストックに入れたのは言うまでもありません。 やった後に気づいたのですが、Qiitaのトレンドも似たようなものなので、結果は近しい内容になるかと思いましたがそうでもなかったです。 この記事だと、トレンドは打率で判断しているようでした。 Qiitaのトレンド表示機能についての考察 違う切り口で記事を拾ってみると、思わぬ掘り出し物が見つかるかもしれないですね。 ソースコードと開発のあれこれ 開発環境 Node v16.10.0 axios 0.22.0 最終的に出来上がったソースコードは次の通り。 qiita.rb const axios = require('axios'); var day = new Date(); var tday = new Date(); //今日 var bday = new Date(tday.setMonth(tday.getMonth()-1)); async function main() { let response = await axios.get( 'https://qiita.com/api/v2/items?page=1&per_page=100&query=stocks:>3000')  //'https://qiita.com/api/v2/items?page=1&per_page=100&query=created:>2021-09-13+stocks:>30') for (let i = 0; i < response.data.length; i++) { //response.data.length var xday = new Date(response.data[i].created_at); //86400000は1日、*24で時間、*60で分 var termDay = (day - xday) / 86400000; //1時間で1いいねを1勢いで計算 var ikioi = response.data[i].likes_count / termDay; console.log(i,response.data[i].likes_count,response.data[i].created_at,termDay,ikioi,response.data[i].url); } } main(); ↓便宜上、記事の取得はストック数で制限をかけています これにたどり着くまでが長かった。。。 検索時に利用できるオプション qiita.rb let response = await axios.get( 'https://qiita.com/api/v2/items?page=1&per_page=100&query=stocks:>3000')  //'https://qiita.com/api/v2/items?page=1&per_page=100&query=created:>2021-09-13+stocks:>30') 感想 手探りでのはじめてのjavascriptでしたが、思った以上に大変でした。 困ったらGoogle先生に聞く、Qiitaの先人たちの記事を見る等、解決策はあるのでしょうが、目当ての情報を得るまでに時間がかかる。調べる力も実力のうちだということを思い知った次第です。 ひとまずはエンジニアとして再出発です。(もう40手前ですが。。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む