- 投稿日:2020-12-27T23:38:23+09:00
JavaScript DOM操作による要素へのアクセス
class属性、セレクタで要素にアクセスする
class="weather"
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>JavaScript Practice</h1> <dl> <dt>今日の天気</dt> <dd class="weather">晴れ</dd> </dl> <script src="index.js"></script> </body> </html>1,class属性やセレクタで要素を取得する
document.querySelector("クラス名");
index.js// querySelectorでweatherのクラスがついている要素を取得 let element1 = document.querySelector(".weather"); console.log(element1); // querySelectorでdlセレクタ要素を取得 let element2 = document.querySelector("dl"); console.log(element2); // DOMのツリー構造を踏まえて指定が可能 let element3 = document.querySelector("dl dt"); console.log(element3);2,コンソール表示結果
3,主な要素取得メソッド
index.js// 主な要素取得メソッド document.getElementById("引数"); //id名 document.getElementsByClassName("引数"); //class名 document.getElementsByTagName("引数"); //要素名 document.getElementsByName("引数"); //name属性 document.querySelector("引数"); //セレクタ document.querySelectorAll("引数"); //セレクタ
- 投稿日:2020-12-27T23:38:23+09:00
JavaScript DOM操作による要素へのアクセス
class属性、セレクタで要素にアクセスする
class="weather"
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>JavaScript Practice</h1> <dl> <dt>今日の天気</dt> <dd class="weather">晴れ</dd> </dl> <script src="index.js"></script> </body> </html>1,class属性やセレクタで要素を取得する
document.querySelector("クラス名");
index.js// querySelectorでweatherのクラスがついている要素を取得 let element1 = document.querySelector(".weather"); console.log(element1); // querySelectorでdlセレクタ要素を取得 let element2 = document.querySelector("dl"); console.log(element2); // DOMのツリー構造を踏まえて指定が可能 let element3 = document.querySelector("dl dt"); console.log(element3);2,コンソール表示結果
3,主な要素取得メソッド
index.js// 主な要素取得メソッド document.getElementById("引数"); //id名 document.getElementsByClassName("引数"); //class名 document.getElementsByTagName("引数"); //要素名 document.getElementsByName("引数"); //name属性 document.querySelector("引数"); //セレクタ document.querySelectorAll("引数"); //セレクタ
- 投稿日:2020-12-27T23:11:53+09:00
javascriptの++iはi++より早いのか?
C言語やjavascriptなどのプログラミング言語にはインクリメント演算子がある。
インクリメント演算子は変数の数値を1加算する動作する。
i++ // 後置インクリメント ++i // 前置インクリメントインクリメント演算子には前置インクリメントと後置インクリメントがあり、違いは評価値が違うこと。
前置インクリメントは1加算したあとの値、後置インクリメントは1加算する前の値を評価値として返す。C言語では++iはi++より早い
C言語だと++iはi++よりパフォーマンスが良い。以下の記事が参考になる。
http://daria-sieben.hatenablog.com/entry/2015/08/21/212605
この記事によると++iはi++に比べて一時的な変数を使用しないため動作が早いようだ。
jsでも検証してみた
検証コード↓
const TIMES = 1000000; let tmp = 0; function test1() { for (let i = 0; i < TIMES ; ++i) { ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; ++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp;++tmp; } } function test2() { for (let i = 0; i < TIMES ; ++i) { tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++;tmp++; } } performance.mark('test1Begin'); test1(); performance.mark('test1End'); performance.mark('test2Begin'); test2(); performance.mark('test2End'); performance.measure( 'test1', 'test1Begin', 'test1End' ); performance.measure( 'test2', 'test2Begin', 'test2End' ); console.log(performance.getEntriesByName('test1')[0]); console.log(performance.getEntriesByName('test2')[0]);結果
++i: 169ms
i++: 169msほぼ同じだったのでjavascriptでは前置後置のパフォーマンスの違いを意識しなくて良いようだ。
- 投稿日:2020-12-27T23:10:24+09:00
Self-organization mapをJavaScriptで実装した
はじめに
「色々な機械学習処理をブラウザ上で試せるサイトを作った」中で実装したモデルの解説の十二回目です。
今回はSelf-organization map(自己組織化マップ)の実装について解説します。
デモはこちらから。(TaskをClusteringにして、ModelのSelf-organization mapを選択)
実際のコードはsom.jsにあります。なお、可視化部分については一切触れません。
概説
こちらのQiitaの記事に全て書いてあります。
これの潜在空間を多次元に対応させつつ、JavaScriptで実装しました。
潜在空間の多次元化は初期化が面倒なだけで、他の処理は難しくありません。
また、その初期化はグリッドを作成しているだけです。Pythonであればnumpy.meshgrid
とzip
あたりを使えば簡単だと思います。コード
SOM
class SOM { // https://qiita.com/tohru-iwasaki/items/e51864269767ccc07254 constructor(input_size, output_size, resolution = 20) { this.in_size = input_size; this.out_size = output_size; this.resolution = resolution; this._sigma0 = 1; this._init_method = 'PCA'; this._epoch = 0; this._z = []; let z0 = Array(output_size).fill(0); do { this._z.push([].concat(z0)); for (let i = output_size - 1; i >= 0; i--) { z0[i]++; if (z0[i] < this.resolution) break; z0[i] = 0; } } while (z0.reduce((a, v) => a + v, 0) > 0); this._y = null; } get _sigma() { return Math.max(this._sigma0 * (1 - this._epoch / 20), 0.2) } _z_distance(i, j) { let d = 0; for (let k = 0; k < this.out_size; k++) { d += (this._z[i][k] - this._z[j][k]) ** 2; } return d; } _find_near_idx(x) { const n = x.length; const dim = this.in_size; const near_idx = []; for (let i = 0; i < n; i++) { let min_d = Infinity; let min_idx = -1; for (let k = 0; k < this._y.length; k++) { let d = 0; for (let j = 0; j < dim; j++) { d += (x[i][j] - this._y[k][j]) ** 2 } if (d < min_d) { min_d = d; min_idx = k; } } near_idx.push(min_idx); } return near_idx; } fit(data) { const x = data; const n = x.length; const dim = this.in_size; if (!this._y) { if (this._init_method === 'random') { this._y = Matrix.randn(this._z.length, dim).toArray(); } else if (this._init_method === 'PCA') { const x0 = new Matrix(n, dim, data) const xd = x0.cov(); const [l, pca] = xd.eigen(); const sl = l.reduce((s, v) => s + v); const expl = new Matrix(1, l.length, l.map(v => Math.sqrt(v))); expl.repeat(this._z.length, 0) expl.mult(x0.select(0, 0, this._z.length, l.length)) this._y = expl.dot(pca.t).toArray() } } const near_idx = this._find_near_idx(x); const r = []; for (let i = 0; i < n; i++) { r[i] = []; const z = this._z[near_idx[i]]; for (let k = 0; k < this._z.length; k++) { let d = this._z_distance(near_idx[i], k); r[i][k] = Math.exp(-d / (2 * this._sigma ** 2)); } } for (let k = 0; k < this._y.length; k++) { let num = Array(dim).fill(0), den = 0; for (let i = 0; i < n; i++) { den += r[i][k] for (let j = 0; j < dim; j++) { num[j] += r[i][k] * x[i][j]; } } for (let j = 0; j < dim; j++) { this._y[k][j] = num[j] / den; } } this._epoch++; } predict(x) { const near_idx = this._find_near_idx(x); return near_idx.map(i => this._z[i]) } }
- 投稿日:2020-12-27T23:08:43+09:00
JavaScript DOM操作でHTML要素を書き換える
<dd>タグにidが設定されているのでid名を指定して対象のHTML要素を書き換えます!
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>JavaScript Practice</h1> <dl> <dt>今日の天気</dt> <dd id="weather">晴れ</dd> </dl> <script src="index.js"></script> </body> </html>1,要素を取得し書き換える
document.getElementById("id名");
index.js// DOM操作でHTMLを書き換える let element = document.getElementById("weather"); // innnerHTMLは記述したテキストもHTMLとして認識 element.innerHTML="<span>曇り</span>"; // textContentは記述したテキストを文字列として認識 element.textContent="<span>曇り</span>";
- 投稿日:2020-12-27T23:08:43+09:00
JavaScript DOM操作でHTML要素を書き換える
<dd>タグにidが設定されているのでid名を指定して対象のHTML要素を書き換えます!
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>JavaScript Practice</h1> <dl> <dt>今日の天気</dt> <dd id="weather">晴れ</dd> </dl> <script src="index.js"></script> </body> </html>1,要素を取得し書き換える
document.getElementById("id名");
index.js// DOM操作でHTMLを書き換える let element = document.getElementById("weather"); // innnerHTMLは記述したテキストもHTMLとして認識 element.innerHTML="<span>曇り</span>"; // textContentは記述したテキストを文字列として認識 element.textContent="<span>曇り</span>";
- 投稿日:2020-12-27T20:48:43+09:00
js.DOMの基本
ブラウザは、htmlを読み込むと内部的にDOM(Document Object Model)と呼ばれるデータ構造が作られて、その内容に応じてページが描画がされる、という仕組みになっている。
- 投稿日:2020-12-27T20:23:47+09:00
【Railsアプリ】販売手数料をJavaScriptで計算しようとしたら出てくる「NaN」を解決できたので、備忘録として残しておきます。
ミス内容
入力された金額の販売手数料(10%)を、JavaScriptを使って計算しようという実装を行っていた時に突如現れた「NaN」。
最初のコードは以下の通り。function calc (){ // id="item-priceの要素を取得。 const itemPrice = document.getElementById("item-price"); // 値が入力された時にイベントを発火。 itemPrice.addEventListener('input', function(){ const Tax = 0.1; const tax_fee = itemPrice * Tax; const profit = itemPrice - tax_fee; const taxArea = document.getElementById("add-tax-price"); const profitArea = document.getElementById("profit"); taxArea.innerHTML = tax_fee; profitArea.innerHTML = profit; }) } window.addEventListener('load', calc)原因
NaN = Not-a-Number(数字ではない)
計算しようとしている値が数字になっていないよ、と伝えているようです。上記のコードだと、
getElementByIdで取得した「要素」と、
Tax=0.1という「数値」をかけ算しようとしている。つまり、要素の値を取得した上で、
「数値」と「数値」をかけ算しなければならないのです><解決法
itemPrice.valueで、要素の「値(=数値)」を取得しましょう。
function calc (){ // id="item-priceの要素を取得。 const itemPrice = document.getElementById("item-price"); // 値が入力された時にイベントを発火。 itemPrice.addEventListener('input', function(){ // 下記を追記して、要素の値を取得。 const itemPriceValue = itemPrice.value const Tax = 0.1; const tax_fee = itemPriceValue * Tax; const profit = itemPriceValue - tax_fee; const taxArea = document.getElementById("add-tax-price"); const profitArea = document.getElementById("profit"); taxArea.innerHTML = tax_fee; profitArea.innerHTML = profit; }) } window.addEventListener('load', calc)これで「NaN」が消え、計算機能を実装することができました!
おわりに
最初、「NaN」ってナンだよ、、、と思いましたが、要素と数値はかけ算できないという初歩的なミスでした。
このミスを解説してくれたメンターさんが仰った『JavaScriptはHTMLをほじくりまわす言語だ』の一言がなぜか胸に刺さりました^^
プログラミングは面白い。もっと使いこなしたいです。
- 投稿日:2020-12-27T20:08:02+09:00
【JavaScript】 JSONをオブジェクトに変換 parseメソッド
JSON.parseメソッドとは?
JSON形式で書かれた文字列をJavaScriptのJSONオブジェクトに変換するメソッドです。
変換した場合は、JavaScriptの中でJSONのデータを自由に扱えるようになります。書き方
変数 = JSON.parse(変換するJSON [, 関数])実装例
const json = '{"firstName":"太郎","lastName":"山田"}'; const obj = JSON.parse(json); // =>JSONをJavaScriptのオブジェクトに変換 console.log(obj.firstName); // =>太郎 console.log(obj.lastName); // =>山田parseメソッドの引数に関数を使用する
以下はキーがfirstNameのとき、値をたろうで返し、それ以外はそのまま返します。
指定したキー(firstName)の値のみが変更されています。const json = '{"firstName":"太郎","lastName":"山田"}'; const a = JSON.parse(json,(key,value)=>{ if (key=="firstName") { return "たろう" ; } return value ; } ) ; console.log(a); // =>{firstName: "たろう", lastName: "山田"}参照
- 投稿日:2020-12-27T19:23:21+09:00
リボルバーリストの作成
円形のリストを表示し、スクロールと連動して回転するピストルのリボルバーのような
アニメーションをするリストの作成デモページ
https://syogo-suganoya.github.io/revolver/
ソース
https://github.com/Syogo-Suganoya/revolver
説明
リストの作成
回転用のリストの作成をします
CSSで子要素の表示を維持しつつ、要素を回転させる方法
https://www.nxworld.net/css-element-rotate.htmlこちらの記事を参考に画面作成をします
今回はスクロールとともに回転させる動きを実装するので、下記をはじめとするのanimation部分は不要です
ul { animation: rotate 30s linear infinite; }スクロールアニメーション
CSS と jQuery で作るスクロールにあわせて回転するロゴ
https://hyper-text.org/archives/2013/07/css_spin_logo.shtm
こちらの記事を参考にスクロールアニメーションを実装します
jsで指定してるセレクタを調整します変更前$(window).scroll(function(){ rotate($(".logo"), $(window).scrollTop()*0.2); })変更後const selList = ['twitter', 'facebook', 'pinterest', 'instagram', 'google']; const listCnt = selList.length; $(window).scroll(function () { // 1回転する角度 var angle = $(window).scrollTop(); // 180pxスクロールするごとに72度回転する angle = Math.round(angle / 180) * (360 / listCnt); rotate($("ul"), angle); rotate($("ul > li"), angle * -1); })選択中リストの動的更新
<p class="select-menu"> twitter </p>選択中のメニューを表示している箇所の動的書き換えをjsで実装します
// 選択中リストの動的更新 roleCnt = angle / (360 / listCnt); // 回転数がリストの要素以上なら要素数分マイナスする while(true) { if (roleCnt < listCnt) { break; } roleCnt -= listCnt; } var selText = selList[roleCnt]; $(".select-menu").text(selText);これで完成です
備考
元ネタはドラマ「リッチマン、プアウーマン」に出てくる「パーソナルファイル」という架空のWebアプリのUIがこのリボルバーリストのような挙動をしていたので試してみましたw
いつかパーソナルファイルが開発されて転入届などがネットで完結できるようになってくれることを期待しています
【公式】リッチマン、プアウーマン
https://fod.fujitv.co.jp/s/genre/drama/ser4389/
- 投稿日:2020-12-27T18:33:19+09:00
[React] JavaScriptのクラスとReact
JavaScriptのクラスとReact
※ 個人用の覚え書きでございます。
JavaScriptのクラス(継承)
script.jsclass Class_1{ constructor(name, age) { this.name = name; this.age = age; } info() { console.log(`名前は${this.name}です`); console.log(`${this.age}歳です`); } } class Class_2 extends Class_1 { } const class_2 = new Class_2("山田",20); class_2.info();React(ボタンをクリックすると表示が切り替わる)
app.jsimport React from 'react'; class App extends React.Component { constructor(props) { super(props); this.state = {name: '山田'}; } handleClick(f_name){ this.setState({name: f_name}); } render() { return ( <div> <h1>こんにちは、{this.state.name}さん!</h1> <button onClick={ () => {this.handleClick('山田')}}> 山田 </button> <button onClick={ () => {this.handleClick('田中')}}> 田中 </button> </div> ); } } export default App;
- 投稿日:2020-12-27T18:22:00+09:00
【Vue 2.x】Composition API の readonly と shallowReadonly で気を付けること
TL;DR
@vue/composition-api
v1.0.0-beta.21 からreadonly()
,shallowReadonly()
が提供されるようになったreadonly()
は引数で受け取ったオブジェクトの型を DeepReadonly 化して返しているだけであるshallowReadonly()
は Vue 3 のものとほぼ同じように使える
readonly()
とshallowReadonly()
とは?
readonly()
は Vue 3 ではリリース時から提供されているリアクティビティ API で、リアクティブな状態を受け取ってリードオンリーなリアクティブな状態を返すことを目的とする関数です。
readonly()
のコード例1
// Vue 3 import { reactive, readonly } from 'vue'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = readonly(original); original.countA++; copy.countA++; // Set operation on key "countA" failed: target is readonly. original.foo.countB++; copy.foo.countB++; // Set operation on key "countB" failed: target is readonly. console.log(original.countA); // 1 console.log(copy.countA); // 1 console.log(original.foo.countB); // 1 console.log(copy.foo.countB); // 1
shallowReadonly()
も Vue 3 ではリリース時から提供されているリアクティビティ API で、readonly()
との違いはリードオンリーになる範囲がオブジェクトの第1階層の値に限定される点です。
shallowReadonly()
のコード例1
// Vue 3 import { reactive, shallowReadonly } from 'vue'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = shallowReadonly(original); original.countA++; copy.countA++; // Set operation on key "countA" failed: target is readonly. original.foo.countB++; copy.foo.countB++; // ブラウザのコンソール上に警告が出ない console.log(original.countA); // 1 console.log(copy.countA); // 1 console.log(original.foo.countB); // 2 console.log(copy.foo.countB); // 2
ユースケース
readonly()
を用いることでprovide()
や props などによって子コンポーネントに状態を渡す際、子コンポーネント側からの状態の変更を防ぐことができます。
このことは Vue 3 ドキュメントのリアクティブの基礎 - readonly でリアクティブオブジェクトの変更を防ぐにも記載があります:例えば、provide されたリアクティブオブジェクトがある場合、それが注入された場所からの変更は防ぎたいことがあります。そうするために、元のオブジェクトに対する読み取り専用のプロキシを作成します
Vue 2 の
readonly()
とshallowReadonly()
についてVue 2 では Composition API は
@vue/composition-api
プラグインとして提供されていますが、@vue/composition-api
v1.0.0-beta.21 から Vue 2 向けにreadonly()
,shallowReadonly()
が提供されるようになりました。
readonly()
は Vue 3 のものとは全く異なる
@vue/composition-api
でのreadonly()
の実装2を確認すると、引数で受け取ったオブジェクトの型を DeepReadonly 化して返しているだけであることがわかります。そのため TypeScript による型チェックをすり抜けてしまった場合3、Vue 3 の
readonly()
とは異なり状態の変更ができてしまいます:// Vue 2 import { reactive, readonly } from '@vue/composition-api'; const original = reactive({ countA: 0, foo: { countB: 0, }, }); const copy = readonly(original); original.countA++; copy.countA++; // ブラウザのコンソール上に警告が出ない original.foo.countB++; copy.foo.countB++; // ブラウザのコンソール上に警告が出ない console.log(original.countA); // 2 console.log(copy.countA); // 2 console.log(original.foo.countB); // 2 console.log(copy.foo.countB); // 2
shallowReadonly()
は Vue 3 のものとほぼ同じように使える
shallowReadonly()
は Vue 3 のものと同様にリードオンリーになる範囲がオブジェクトの第1階層の値に限定されますが、Vue 3 のものとほぼ同じように使うことができます。Vue 2 では場合によっては
readonly()
よりもshallowReadonly()
を使った方が良いことがあります。
例えば、各プロパティの値がすべてプリミティブ型であるようなオブジェクトにはshallowReadonly()
を用いることでreadonly()
よりも確実に状態の変更を防ぐことができます:// Vue 2 import { reactive, readonly, shallowReadonly } from '@vue/composition-api'; // 各プロパティの値がすべてプリミティブ型(string | number | boolean)である const original = reactive({ text1: '', text2: '', text3: '', number1: 0, number2: 0, }); // Not good const copy1 = readonly(original); // Better const copy2 = shallowReadonly(original);
Vue 2 の
shallowReadonly()
にはできないことについて
@vue/composition-api
でのshallowReadonly()
の実装4を確認すると、引数で受け取ったオブジェクトの(第1階層の)キーでループを回し5、別途定義したオブジェクトに対して同じキーを持つプロパティを定義する6実装となっていることがわかります。
そのためshallowReadonly(obj)
実行時にobj
が持っているプロパティの値に限ってリードオンリーとすることができます。// Vue 2 import { reactive, shallowReadonly } from '@vue/composition-api'; const original = reactive({ countA: 100, }); const copy = shallowReadonly(original); original.countB = 200; console.log(copy.countA); // 100 console.log(copy.countB); // undefined// Vue 3 import { reactive, shallowReadonly } from 'vue'; const original = reactive({ countA: 100, }); const copy = shallowReadonly(original); original.countB = 200; console.log(copy.countA); // 100 console.log(copy.countB); // 200
2020/12/27 時点でリリースされていない Vue 3 の IE11 互換ビルドを利用すると Vue 3 の
readonly()
,shallowReadonly()
の挙動が本記事で想定しているものと異なるものとなる可能性があります ↩
@vue/composition-api
v1.0.0-beta.22 でのreadonly()
の実装: https://github.com/vuejs/composition-api/blob/v1.0.0-beta.22/src/reactivity/readonly.ts#L42-L46 ↩特に Vue では
<template>
上のv-model
など型チェックが効きにくい場所があったりします ↩
@vue/composition-api
v1.0.0-beta.22 でのshallowReadonly()
の実装: https://github.com/vuejs/composition-api/blob/v1.0.0-beta.22/src/reactivity/readonly.ts#L48-L97 ↩
for (const key of Object.keys(obj)) { ... }
の部分 ↩
Object.defineProperty(readonlyObj, key, { ... })
の部分 ↩
- 投稿日:2020-12-27T17:54:42+09:00
QuickJSでお手軽ESP32+Javascript実行環境
@binzume さんが投稿をされて、ESP32でもJavascriptが動くことを知りました。( ESP32 と QuickJS で小さなJavaScript実行環境を作る )
しかもES2020に対応しているなんて素敵です。以下のことができることを目指します。
- console.logがSerial出力されること(これはすでに@binzumeさんが実装されています)
- LCD、Wire(I2C)、GPIOをJavascriptから触れるようにします。
- JavascriptのソースコードをWebから取得します。
3番目が今回のモチベーションで、ESP32起動時にネットワークから取得することで、PlatformIOやArduino IDEから毎度コンパイル・書き込みを行う必要がなくなります。動作確認が終わったら、ROMに埋め込みます。
毎度の通りGitHubに上げておきます。
poruruba/Esp32QuickJS_sample
https://github.com/poruruba/Esp32QuickJS_sampleQuickJSの用意
@binzumeさんがすでにGitHubにライブラリ化していただいていますので、心配することはありません。
binzume/esp32quickjs
https://github.com/binzume/esp32quickjsオリジナルのQuickJSは以下にあります。
bellard/quickjs
https://github.com/bellard/quickjs
https://bellard.org/quickjs/PlatformIOプロジェクトの作成
それではESP32用にJavascript実行環境を作成します。
まずは、PlatformIOのプロジェクトを作成します。名前はなんでもよいのですが、とりあえず「Esp32QuickJS」とでもしておきます。
Boardには、今回M5Stick-Cを使いました。次に、platformio.iniを編集します。
そうです、@binzumeさんが用意していただいているライブラリを指定します。また、同様にtanakamasayukiさんの「ESP32 Lite Pack Library」も使わせていただきました!platform.ini[env:m5stick-c] platform = espressif32 board = m5stick-c framework = arduino upload_port = COM6 monitor_port = COM6 lib_deps = tanakamasayuki/ESP32 Lite Pack Library@^1.3.2 https://github.com/binzume/esp32quickjs.git#v0.0.1 board_build.partitions = no_ota.csv board_build.embed_txtfiles = src/default.js ; src/main.js次に、srcフォルダにdefault.jsを置きます。これは、WebからJavascriptのダウンロードに失敗したときに実行するもので、バカ除けです。
src/default.jsconsole.log("start"); setInterval(() =>{ console.log('http get failed'); }, 1000);ESP32用のQuickJSの呼び出し
まずは、mainとなるmain.cppです。
src/main.cpp#include <WiFi.h> #include "M5Lite.h" #include <HTTPClient.h> #include "quickjs_esp32.h" //#define LOCAL_JAVASCRIPT // ROMに埋め込む場合にはコメントアウトを外す const char *wifi_ssid = "【WiFiアクセスポイントのSSID】"; const char *wifi_password = "【WiFiアクセスポイントのパスワード】"; const char *jscode_url = "【Javascriptの取得先URL】"; // see platformio.ini #ifdef LOCAL_JAVASCRIPT extern const char jscode_main[] asm("_binary_src_main_js_start"); #else extern const char jscode_default[] asm("_binary_src_default_js_start"); #define JSCODE_BUFFER_SIZE 10000 char jscode[JSCODE_BUFFER_SIZE]; unsigned long jscode_len = sizeof(jscode); WiFiClient espClient; WiFiClientSecure espClientSecure; void wifi_connect(const char *ssid, const char *password); long doHttpGet(String url, uint8_t *p_buffer, unsigned long *p_len); #endif ESP32QuickJS qjs; void setup() { M5Lite.begin(); Serial.begin(9600); M5Lite.Lcd.setRotation(3); M5Lite.Lcd.fillScreen(BLACK); M5Lite.Lcd.setTextColor(WHITE, BLACK); M5Lite.Lcd.println("[M5StickC]"); #ifdef LOCAL_JAVASCRIPT qjs.begin(); qjs.exec(jscode_main); #else wifi_connect(wifi_ssid, wifi_password); long ret; ret = doHttpGet(jscode_url, (uint8_t*)jscode, &jscode_len); if( ret == 0 ){ jscode[jscode_len] = '\0'; qjs.begin(); qjs.exec(jscode); }else{ qjs.begin(); qjs.exec(jscode_default); } #endif } void loop() { M5Lite.update(); qjs.loop(); // For timer, async, etc. if (M5Lite.BtnB.wasPressed()) { Serial.println("BtnB pressed"); esp_restart(); } } #ifndef LOCAL_JAVASCRIPT void wifi_connect(const char *ssid, const char *password){ Serial.println(""); Serial.print("WiFi Connenting"); M5Lite.Lcd.print("Connecting"); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); M5Lite.Lcd.print("."); delay(1000); } Serial.println(""); Serial.print("Connected : "); Serial.println(WiFi.localIP()); M5Lite.Lcd.fillScreen(BLACK); M5Lite.Lcd.setCursor(0, 0); M5Lite.Lcd.println(WiFi.localIP()); } long doHttpGet(String url, uint8_t *p_buffer, unsigned long *p_len){ HTTPClient http; Serial.print("[HTTP] GET begin...\n"); // configure traged server and url if( url.startsWith("https") ) http.begin(espClientSecure, url); //HTTPS else http.begin(espClient, url); //HTTP Serial.print("[HTTP] GET...\n"); // start connection and send HTTP header int httpCode = http.GET(); unsigned long index = 0; // httpCode will be negative on error if(httpCode > 0) { // HTTP header has been send and Server response header has been handled Serial.printf("[HTTP] GET... code: %d\n", httpCode); // file found at server if(httpCode == HTTP_CODE_OK) { // get tcp stream WiFiClient * stream = http.getStreamPtr(); // get lenght of document (is -1 when Server sends no Content-Length header) int len = http.getSize(); Serial.printf("[HTTP] Content-Length=%d\n", len); if( len != -1 && len > *p_len ){ Serial.printf("[HTTP] buffer size over\n"); http.end(); return -1; } // read all data from server while(http.connected() && (len > 0 || len == -1)) { // get available data size size_t size = stream->available(); if(size > 0) { // read up to 128 byte if( (index + size ) > *p_len){ Serial.printf("[HTTP] buffer size over\n"); http.end(); return -1; } int c = stream->readBytes(&p_buffer[index], size); index += c; if(len > 0) { len -= c; } } delay(1); } } } else { http.end(); Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); return -1; } http.end(); *p_len = index; return 0; } #endifLOCAL_JAVASCRIPT がDefineされているかどうかで変わります。
定義されていない場合、Wifiに接続し、指定された【Javascriptの取得先URL】からHTTP GetでJavascriptをダウンロードしそれを実行しています。
WiFiアクセスポイントは以下で指定します。
【WiFiアクセスポイントのSSID】
【WiFiアクセスポイントのパスワード】Javascriptの実行は以下の部分です。
src/main.cppqjs.begin(); qjs.exec(jscode);実行エンジンは以下で指定しています。実行エンジンの実装は後ほど説明します。
src/main.cpp#include "quickjs_esp32.h" ESP32QuickJS qjs;Javascriptの動作の確認ができたら、WiFiから取得するのではなくROMに埋め込みます。
その場合は、LOCAL_JAVASCRIPTをDefine定義して、以下にファイルを配置します。src/main.jsplatform.iniで上記ファイルを定義し、以下のようにしてCソースから取り出せます。
extern const char jscode_main[] asm("_binary_src_main_js_start");ちなみに、すぐにWeb上のJavascriptを再ロードできるように、M5StickCのBボタン(右側面にあるボタン)を押せば、リブートがかかるようにしています。
ESP32用のQuickJSの実装
Javascript実行エンジンは、ESP32に特化してカスタマイズしており、ヘッダファイル
include/quickjs_esp32.h
に記述しています。
※というより、ほぼ @binzume さんのオリジナルです。
ちなみに、QuickJS本体は、@binzumeさんのライブラリを参照しておりquickjs.h
にあります。ソースコードが長いので、詳細はGitHubをご参照ください。
なんかだらだらと長いですが、JavascriptからLCDやI2CやGPIOをたたくためのラッパーを実装しています。
コマンド名は、デバイスタイプごとにサポートする名前が異なります。
整理する意味でざっと上げてみました。
デバイス名 コマンド名 gpio pinMode ^ digitalWrite ^ digitalRead ^ analogRead wire begin ^ requestFrom ^ beginTransmission ^ endTransmission ^ write ^ available ^ read wire1 begin ^ requestFrom ^ beginTransmission ^ endTransmission ^ write ^ available ^ read lcd setRotation ^ setTextColor ^ setTextSize ^ setCursor ^ setBrightness ^ drawPixel ^ drawLine ^ ^ println ^ fillScreen ^ getWidth ^ getHeight ^ getDepth Javascriptを実行
それでは、Javascriptを実行してみます。
1秒ごとにLEDをついたり消したりするLチカアプリです。
GPIOの操作には以下のgpioを使います。import * as gpio from "gpio";例えばこんな感じです。
main.jsimport * as esp32 from "esp32"; import * as gpio from "gpio"; import * as lcd from "lcd"; console.log("start"); gpio.pinMode(10, gpio.OUTPUT); var led = false; gpio.digitalWrite(10, led ? gpio.LOW : gpio.HIGH); lcd.println("Hello World"); lcd.setTextSize(2); setInterval(async () =>{ try{ console.log('interval'); led = !led; gpio.digitalWrite(10, led ? gpio.LOW : gpio.HIGH); }catch(error){ console.log(error); } }, 1000);これを、
src/main.cpp
で指定した【Javascriptの取得先URL】に配備します。
それでは、PlatformIOからコンパイル・書き込みを実施し、M5StickCを起動させてみましょう。
WiFiアクセスポイントに接続後、LCDにHello Worldと表示され、1秒ごとにLEDが付いたり消えたりしたのではないでしょうか。(応用)ENV Sensorで温度を計測
Groveで接続可能なセンサーユニットを使います。
M5Stack用環境センサユニット
https://www.switch-science.com/catalog/5690/
(おうっ、販売終了しているではないか。。。)I2Cで接続します。
I2Cの操作には、lcdを使います。import * as lcd from “lcd”;こんな感じです。
main.jsimport * as esp32 from "esp32"; import * as gpio from "gpio"; import * as wire from "wire"; import * as lcd from "lcd"; console.log("start"); gpio.pinMode(10, gpio.OUTPUT); var led = false; gpio.digitalWrite(10, led ? gpio.LOW : gpio.HIGH); lcd.println("Hello World"); lcd.setTextSize(2); class DHT12{ constructor(wire, scale = 1, id = 0x5c){ this.CELSIUS = 1; this.KELVIN = 2; this.FAHRENHEIT = 3; this.wire = wire; this.scale = scale; this.address = id; } async read(){ this.wire.beginTransmission(this.address); var ret = this.wire.write(0); if( ret != 1 ) throw 'failed'; var ret = this.wire.endTransmission(); if( ret != 0 ) throw 'failed'; var ret = this.wire.requestFrom(this.address, 5); if( ret != 5 ) throw 'failed'; var datos = this.wire.read(5); await this.sleep_async(50); var ret = this.wire.available(); if( ret != 0 ) throw 'failed'; if (datos[4] != (datos[0] + datos[1] + datos[2] + datos[3]) ) throw 'datos error'; this.datos = datos; } async readTemperature(scale){ await this.read(); if( scale == undefined ) scale = this.scale; var resultado = 0.0; switch(scale) { case this.CELSIUS: resultado = this.datos[2] + this.datos[3] / 10.0; break; case this.FAHRENHEIT: resultado= (this.datos[2] + this.datos[3] / 10.0) * 1.8 + 32.0; break; case this.KELVIN: resultado= (this.datos[2] + this.datos[3] / 10.0) + 273.15; break; }; return resultado; } async readHumidity(){ await this.read(); var resultado = (this.datos[0] + this.datos[1] / 10.0); return resultado; } async sleep_async(msec){ return new Promise(resolve =>{ setTimeout(resolve, msec); }); } } wire.begin(); var dht12 = new DHT12(wire); lcd.println("DHT12 start"); setInterval(async () =>{ try{ console.log('interval'); led = !led; gpio.digitalWrite(10, led ? gpio.LOW : gpio.HIGH); var temp = await dht12.readTemperature(); console.log(temp); }catch(error){ console.log(error); } }, 1000);うまくいけば、SerialコンソールとLCDに温度が表示されているかと思います。
終わりに
QuickJSを作ってくれたbellardさんに感謝ですし、見つけてくれた@binzumeさんにも感謝です!
HTTP Getによるファイルダウンロードは以下を参考にしています。
ESP32でバイナリファイルのダウンロード・アップロードもし、Javascript(Node.js)上で、ブレークポイントを入れたりとデバッグしたい場合は以下もご検討ください。DHT12のライブラリはこちらで作成しました。
M5StickCの書き換えが面倒だったので、Node.jsでArduinoっぽくしてみた以上
- 投稿日:2020-12-27T17:54:34+09:00
[PlayCanvas] Rigidbodyを持ったTemplateをinstantiateする時の注意点
はじめに
PlayCanvasに Template という機能が実装されています。
これによりEntityやコンポーネントなどを組み合わせたものをアセットとして保存できるようになり、別シーンでも同じ構成物をいちいち作る必要がありません。
またTemplateをインスタンス化することもできるので、シーンにベースEntityを置いておく必要がなくなりました。まずはインスタンス化
まずは手短にインスタンス化を行います。
Samplevar Generator = pc.createScript('generator'); Generator.attributes.add('tmpl', {type: 'asset', assetType: 'template'}); Generator.prototype.initialize = function() { if( this.tmpl ){ // インスタンス化 var instance = this.tmpl.resource.instantiate(); // インスタンスを子Entityに設定 this.app.root.addChild( instance ); } };インスタンス化と子Entity化はワンセットです。
子Entity化を忘れると表示もされず、メモリの彼方へと消えます。(そして自動開放される)これであとは座標を変えたりして調整すればいいのですが、そこで注意が必要です。
Rigidbodyを持ったTemplateをインスタンス化
コリジョンを持ったEntityをTemplate化することも勿論あると思います。
先程と同じ手順でインスタンス化し{X:0, Y: 10, Z: 0}の座標に設置して、自由落下させようとしたとします。Samplevar Generator = pc.createScript('generator'); Generator.attributes.add('tmpl', {type: 'asset', assetType: 'template'}); Generator.prototype.initialize = function() { if( this.tmpl ){ var instance = this.tmpl.resource.instantiate(); this.app.root.addChild( instance ); instance.setLocalPosition( 0, 10, 0 ); } };ザックリと実装するならばこんな感じでしょうが、これは正常に動作しません。
これを実行すると、インスタンス化したEntityは指定した座標に設置されず、更に他のコリジョンを持つEntityと衝突すると下記のエラーが出ます。Uncaught RuntimeError: memory access out of boundsコンソールを開いて確認するとAmmoが警告を吐いてるので、Rigidbodyを持ったTemplateをインスタンス化直後に座標系を弄ると駄目なようです。(無論、回転も駄目)
対処
ひとまず正常に動作する方法を探した結果、以下の3つの方法が動作するのを確認しました。
Rigidbodyをインスタンス化後にaddする
Templateを作成する時にRigidbodyを外しておき、インスタンス化時にaddComponentでRigidbodyを追加する方法。
細かいパラメータ(反発係数など)を後からセットする手間を考えると現実的じゃない。SampleGenerator.prototype.initialize = function() { if( this.tmpl ){ var instance = this.tmpl.resource.instantiate(); this.app.root.addChild( instance ); instance.setLocalPosition( 0, 10, 0 ); instance.addComponent('rigidbody'); } };RigidbodyをDisable状態でTemplateにする
Template作成時に、Rigidbodyの状態をDisableにしてからTemplateにする方法。
インスタンス化時にEnableにしてあげればよい。SampleGenerator.prototype.initialize = function() { if( this.tmpl ){ var instance = this.tmpl.resource.instantiate(); this.app.root.addChild( instance ); instance.setLocalPosition( 0, 10, 0 ); if( instance.rigidbody ){ instance.rigidbody.enabled = true; } } };rigidbody.teleport()を使用する
そもRigidbodyの機能に依存する方法。
座標だけを変える必要があるならば、この方法が採用できる。SampleGenerator.prototype.initialize = function() { if( this.tmpl ){ var instance = this.tmpl.resource.instantiate(); this.app.root.addChild( instance ); if( instance.rigidbody ){ instance.rigidbody.teleport(0, 10, 0 ); } } };おわりに
こんなん書いてどうするんだと思うかもしれませんが、これを上手く書くとプロジェクト自体を落とせます。
進捗が正常に更新される前に落とされたら最悪プロジェクト自体が死ぬ可能性があるので、共有を…といった感じ。外部リンク
- 投稿日:2020-12-27T16:02:07+09:00
Javascriptの配列とオブジェクトの分割代入とは
こんにちは!
プログラミング初心者のstraw_engineです。
何も知らないことだらけでとりあえず内定先の方からおすすめしていただいたJavaScript本格入門という本のアウトプットをしようかと思います。分割代入とは?
分割代入(配列)
分割代入についてここでは記述します。
分割代入とは配列、もしくはオブジェクトを分解して配下の要素/プロパティを個々の変数に分解するための構文です。
ES2015以前であれば配列から値を取り出すために、一つ一つの要素にアクセスする必要があったそうです。
下記みたいな感じです。var data = [1,2,3,4,5,6]; var x0 = data[0]; var x1 = data[1]; //要素の数だけ書く必要があった。しかし、ES2015以降はとても便利になって、分割代入によってこのめんどくさい作業が一行で済むようになりました。
let data = [1,2,3,4,5,6]; let [x0,x1,x,2,...others] = data; console.log(x0); //結果:1 console.log(x1); //結果:2 console.log(others); //結果:[3,4,5,6]分割代入の際には代入先の変数も[ ]で囲む必要があります。
また、「...」演算子を使用することで、変数に分解されなかった要素を配列で列挙することが可能です。分割代入(オブジェクト)
次にオブジェクトの分割代入について記述します。
Javascriptでは配列と同様にオブジェクトも分割代入を利用できます。
下記のように使用します。let book = { title: 'JavaScript入門書', publish:' straw_engine出版社', price: 2500 }; let { price, title, memo = 'なし' } = book; console.log(title); //結果:JavaScript入門書 console.log(price); //結果:2500 console.log(memo); //結果:なしポイントなのがオブジェクトの場合には名前で一つ一つの変数に分解するということです。
上記の結果でわかるように順番ではなく、名前で分解されており、対応する変数がないpublishはスキップされています。
また、「変数名=デフォルト値」でデフォルト値を設定しておくこともできます。
memoのデフォルト値を「なし」に設定しているので「なし」という結果が返ってきています。・入れ子構造になったオブジェクトの分解
ただ、オブジェクトは入れ子構造になっていることもあります。
そして、入れ子構造になっていても分割代入は利用できます。
入れ子構造になっているオブジェクトを分解するには入れ子の関係がわかるように代入先の変数も{...}で囲みます。let book = { title: 'JavaScript入門書', publish:' straw_engine出版社', price: 2500, other: { memo: 'あいうえお', publisher: 'straw_engine' } }; let { title, other, other: { memo } } = book; console.log(title);//結果:JavaScript入門書 console.log(other);//結果:{memo: "あいうえお", publisher: "straw_engine"} console.log(memo);//結果:あいうえおotherだけ記述した場合には、otherプロパティの中身が代入されますが、入れ子構造を記述することでmemoプロパティを代入しています。
・異なる名前の変数に代入する
先ほどオブジェクトの場合には対応する名前で変数に代入すると述べましたが、
「変数名: 別名」
でプロパティとは異なる名前の変数に値を割り当てることもできます。let book = { title: 'JavaScript入門書', publish:' straw_engine出版社', price: 2500}; let { title: name publish: company} = book; console.log(name); //結果:JacaScript入門書 console.log(company); //結果:straw_engine出版社上記ではtitleとpublishのプロパティを変数nameとcompanyにそれぞれ名前を変えて代入しています。
また、上記では変数の宣言と代入を1文でしていますが、宣言と代入を切り離すことも可能です。let price, title, memo; //変数の宣言 ({ price, title, memo = 'なし' }); //変数の代入まとめ
今回はJavaScript本格入門のアウトプットをしました。
しばらく、この本に沿ってアウトプットをするかと思います。
この本にはもっと詳細にJavaScriptの仕様等について書かれています。
気になった方はぜひ買って確認してみてください。
- 投稿日:2020-12-27T15:19:00+09:00
$(window).on('load')関数がIEだと動かない理由と対処法
問題点
jQueryにて以下のようなコードを書くと\$(window).on('load')の中身が動作しない場合がある。
$(function(){ $(window).on('load', function(){ }); });\$(function()内に\$(window).on('load')関数を記述すると\$(window).on('load')の中身が動作しなくなってしまうのだ。
これは以下のように修正すると動くようになる。$(function(){ }); $(window).on('load', function(){ });関数の実行タイミングについて
なぜ上のような記述でエラーが出てしまうのか、それはJSの実行タイミングが関係してくる。
まず上に出てきた2つの関数の実行タイミングについておさらいする。\$(function()
HTML(DOM)の読み込みが終わったら関数の中の処理を実行する。
\$(window).on('load')
画像などページ内にある全てのリソースの読み込みが終わったら関数の中の処理を実行する。つまり実行される順番としては以下のようになる。
1. HTML(DOM)の読み込みが終わる
2. \$(function()内の処理を実行
3. ページ内にある全てのリソースの読み込みが終わる
4. \$(window).on('load')内の処理を実行原因
前述より今回の不具合に関してはDOMの読み込みが終わり、\$(function()内の処理が実行されたタイミングでは画像などの読み込みが終わっておらず、\$(window).on('load')内の処理が実行されなかったことにより起こっていると考えられる。
これを解消するには最初に記述した通りに、それぞれの関数を分けて記述し、ちゃんと実行順序を示してあげることで解決する。$(function(){ }); $(window).on('load', function(){ });
- 投稿日:2020-12-27T14:03:29+09:00
同期処理、Promise、Async/Awaitで相互にエラーハンドリングする一覧
同期処理と非同期処理の間でエラーを渡す
エラー処理の引き渡しの資料はQiitaでもTipsとしていっぱい転がっている。しかし可能性として有りうる同期処理・Promise・Async/Await相互のエラー受け渡しについて言及したものは少ない。そこで、それらをできるだけ網羅してみたつもりである。
読みやすくなる前提知識は以下。
- 自前のエラーはインスタンスの生成(
new Error
)で作る- エラーはthrowで投げる
- 同期処理中のエラーはtry-catch構文で拾う
- PromiseのエラーはPromise.catchメソッドで拾う
- Async関数内のエラーはthrowで投げ、try-catch構文で拾う
この上で、コードと実行結果を交えて、Uncaughtなエラーをうまく扱っていく。
調べたきっかけ
とあるOSSを使ってみたが、非同期処理の結果が返ってこない。そのときはエラー処理が問題なのかどうかの切り分けができず、苦労することに。
イベントループ、try-catch、非同期処理、Async関数、エラーオブジェクト…
エラーをハンドルしたいだけなのに、なぜこうもMDNのドキュメントを行き来せねばならず、加えて
Promise.all
を紹介されなければならないのか。
それらを深追いした末に、エラーを非同期処理中で発生させたものを同期処理中にしっかりキャッチしてもらうコードを練習するに至った。投稿のきっかけ
私はN予備校生のsatsukizzzです。N予備校のWebプログラミング講座では、Node.jsを用いてサーバーサイドを含めJavaScriptで書くという経験をしました。その後に上記のようなことが起きました。
せっかくある程度のレベルで調べ上げたわけなので、N校受講生用の2020年アドベントカレンダーに…と思っていたのに。年末のやっつけ仕事でやろうとした私がアホで、12/25を最後にアドベントカレンダーは閉幕していました。
一方で私の友人関係では同じようにJavaScriptを使っている人たちも多いため、遅ればせながら投稿することとなりました。環境とブラウザ
- クライアントサイドのJavaScript
- Google Chrome 86.0.4240あたり / Firefox 81.0.1あたり
Node.jsでは確認していない(next関数も重要であることは承知している)。
なお、全てのエラー表示の画像はGoogle Chrome 87.0.4280のDeveloper Toolを用いて取得している。ケース
同期処理から同期処理へ
const tryThrownErrorInSyncToSync = () => { try { throw new Error('in sync'); } catch (e) { console.error(e); } } tryThrownErrorInSyncToSync();Promiseから同期処理へ(uncaught)
const tryRejectedErrorInPromiseToSync = () => { try { new Promise((resolve, reject) => reject(new Error('in promise; this is an uncaught error'))); } catch (e) { console.error(e); } } tryRejectedErrorInPromiseToSync();Async関数から同期処理へ
const rejectAsync = async (errorMessage) => { throw new Error(errorMessage); }; // rejectAsync関数は実はPromiseのエラーを返すなら何にでも変えられる const throwPromise = (errorMessage) => { return new Promise((resolve, reject) => reject(new Error(errorMessage))); }; // つまり、代わりにこのthrowPromise関数でもよい const tryThrownErrorInAsyncToSync = async () => { try { rejectAsync('uncaught async error in reject async'); } catch (e) { console.error(e); } try { await rejectAsync('caught async error in reject async'); } catch (e) { console.error(e); } return; } tryThrownErrorInAsyncToSync();同期処理からPromiseへ;rejectで
new Promise((resolve, reject) => { reject(new Error('catch rejected error in sync to promise')) }) .catch(console.error);同期処理からPromiseへ;throwで
new Promise((resolve, reject) => { throw new Error('catch thrown error in sync to promise; same as rejected one'); }) .catch(console.error);PromiseからPromiseへ;コメント付加
//if you need a Promise object with arguments then make a function which returns Promise object. put that function object in Promise.then or Promise.catch directly as below const returnRejectedPromise = (error) => { return new Promise((resolve, reject) => { error.message = 'rejected in promise, and ' + error.message; reject(error); }); } Promise.reject(new Error('catch rejected error in promise chain')) .catch(returnRejectedPromise) // added some information and re-rejected .catch(console.error); // executed new Promise((resolve, reject) => { returnRejectedPromise(new Error('cannot catch rejected error in promise to promise; please chain those promises')); }) .catch(console.error); // not executedAsync関数からPromiseへ;コメント付加
// using async function instead of returnRejectedPromise const throwPromiseWithAsync = async (error) => { error.message = 'thrown in async, and ' + error.message; throw error; } Promise.reject(new Error('catch rejected error in promise chain')) .catch(throwPromiseWithAsync) // added some information and re-rejected(thrown in async) .catch(console.error); // executed new Promise((resolve, reject) => { throwPromiseWithAsync(new Error('cannot catch thrown error in async to promise; please chain those promises')); }) .catch(console.error); // not executedPromiseから同期処理へ;Resolveしてしまった場合
const promiseCatchResolvedErrorInPromiseToSync = () => { new Promise((resolve, reject) => { resolve(new Error('resolved with an error in promise; this is caught in fulfilled')); }) .then(value => {console.log(value);}) // catches as "value" of the error .catch(error => {console.error(error);}); // not executed } promiseCatchResolvedErrorInPromiseToSync();
つまり、もしエラー終了させたいならthen(value => {console.error(value);})
としてやったらいいとおもう。病気。Promiseから同期処理へ
const promiseCatchRejectedErrorInPromiseToSync = () => { new Promise((resolve, reject) => { reject(new Error('rejected with an error in promise')); }) .catch(e => console.error(e)); } promiseCatchRejectedErrorInPromiseToSync();Promiseから同期処理へ;エラーオブジェクトを生成しなかった場合
const promiseCatchRejectedInPromiseToSync = () => { new Promise((resolve, reject) => { reject('rejected without an error in promise'); }) .catch(e => console.error(e)); } promiseCatchRejectedInPromiseToSync();▼を押して開くと現れる、ブラウザによるスタックトレースのみとなる(エラーオブジェクトのスタックトレースがない)。
async関数からPromiseへ;returnした場合
//Promise内でAsync functionを実行しエラーを伝える const asyncReturnError = async () => { return new Error('returned with an error in async; this is caught in fulfilled'); }; new Promise((resolve, reject) => { asyncReturnError() .then(value => {resolve(value);}) //executed .catch(error => {reject(error);}); }) .then(value => {console.log(value);}) //executed .catch(error => {console.error(error);});エラーオブジェクトのスタックトレースが表示されるが、エラーの色をしていない。
また、ブラウザのスタックトレースが生成されない。async関数からPromiseへ;throwした場合
// throwの場合 const asyncThrowError = async () => { throw new Error('throw an error in async; this is caught in rejected'); }; new Promise((resolve, reject) => { asyncThrowError() .then(value => {resolve(value);}) .catch(error => {reject(error);}); //executed }) .then(value => {console.log(value);}) .catch(error => {console.error(error);}); //executedpromiseからasyncへ
//make errors in Promise and transfer them to Async function async function testErrorsInPromiseToAsync() { try { await new Promise((resolve, reject) => { reject(new Error('rejected in promise to async try block with await(but not useful because the scope of variables is try)')); }); } catch (error) { console.error(error); } new Promise((resolve, reject) => { reject(new Error('error in rejected promise to async function without await; this is uncaught')); }) .catch(error => {throw error;}); await new Promise((resolve, reject) => { reject(new Error('error in rejected promise to async function with await')); }) .catch(error => {throw error;}); } testErrorsInPromiseToAsync() .catch(console.error);おまけ:
setTimeout
のラップpromiseでsetTimeoutをラップ
「setTimeoutはPromiseでラップする」とは例えばこのように。
```JavaScript
const delayedResolve = (ms) => {
return new Promise(resolve => {setTimeout(resolve, ms)});
};const delayedReject = (ms, error) => {
return new Promise((resolve, reject) => {setTimeout(reject(error), ms)});
};
```そのうえで、
const throwAfterTimeout = async () => { await delayedReject(1000, new Error('error in trying delayedReject')) .catch(console.error); } const throwInSetTimeout = async () => { try { await setTimeout(() => { throw new Error('error in trying setTimeout; this is uncaught'); }, 2000); } catch (error) { console.error(error); } } const promiseCatchAfterTimeout = () => { delayedReject(3000, new Error('error in Promise.catching delayedReject')) .catch(console.error); } throwAfterTimeout(); throwInSetTimeout(); promiseCatchAfterTimeout();async関数でsetTimeoutをラップ
const asyncTimeout = async (ms, errorOrValue) => { return new Promise((resolve, reject) => { if(errorOrValue instanceof Error) setTimeout(() => {reject(errorOrValue)}, ms); setTimeout(() => {resolve(errorOrValue);}, ms); }); } asyncTimeout(4000, 'delayed resolve in async timeout') .then(console.log) //executed .catch(console.error); asyncTimeout(4000, new Error('delayed error in async timeout')) .then(console.log) .catch(console.error); //executed雑記
2020-12-27 公開日
この記事は自分自身へのクイックドキュメントとして存在しています。
一方で、気になるエラーや載せてほしい例があれば
- 記事へのコメント
- 私のtwitter: satsukizzzへのアクション(リプライ等) ... Qiita同様スチームミルクを落とす画像
- N予備校slackのsatsukizzzへのアクション(メンション等) ... ピーチティーの画像
をしてもらえれば追加します。そのときは、皆さんのクイックドキュメントになればなと思います。
詳しい方は用語の勘違いの指摘などしていただけると大変ありがたいです。年末のやっつけで2か月前に試したものを一つ一つ切り出しただけであるため、後々整理すると思われますが、閲覧者の疑問点に合わせて分類するのもわかりやすいかな?と思うので、まずは公開しました。
- 投稿日:2020-12-27T13:34:25+09:00
promise、asyncとawaitについて(自分用)
- 非同期処理を行ったあとに、処理を実行したい
- 500ミリ秒後に、helloを実行し、そのあとにworldを実行したい
setTimeout(() => console.log('hello'), 500); console.log('world');
- worldのあとに、helloが実行されてしまった
- さらにコールバックを使って実現してみよう!
setTimeout(() => { console.log('hello'); setTimeout(() => { console.log('world'); }, 500); }, 500);
- できたけど、ネスト化していてわかりづらい(コールバック地獄)
- promiseでわかりやすくかけるらしい
const promise = new Promise((resolve, reject) => { setTimeout(() => { console.log('hello'); resolve(); }, 500); }); promise.then(() => console.log('world!')); console.log('yeah!'); // ここが実行されたあとに、上の2つが実行される
- わかりやすくなった!
- asyncとawaitを組み合わせることでより簡潔にかけるらしい
async function helloWorld(text) { const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(text); }, 5000); }); const val = await promise; // awaitでpromiseの終了を待つ console.log(val); console.log('world!'); } helloWorld('hello'); console.log('Yeah'); // ここが実行されたあとに、上の処理が実行される
- より処理の流れがわかりやすくなった
- 投稿日:2020-12-27T12:53:57+09:00
[Vue.js]Storeの値がcommit以外で変わっちゃった時の話
前書き
業務でNuxt.jsアプリの改修をしていて、
なんかバグ出てるやん
→ どうやらStoreの値中の配列の値がおかしいぞ
→ 変な値がcommitされているんだな
→ commit値は正常だな・・
→ あ、変なところでまたcommitが呼ばれちゃってるんだな!
→ commitは(正常時の)1回しかされていないぞ・・
→ 詰なことがあったので、これを解決した時の話を書いてみます。
体験談
今回のポイントは、異常値を示した値の型が
配列
と言う点。最初はVue初級者が故に、
storeの値はcommitから以外で変わり得ない
、と言う前提はあったため、
VueXの仕様的に誤った使い方しているんじゃ、、と的外れなあたりをつけてVue周りを調べてました。そんな時、ふと配列で思い出したのが、
配列は参照型やん
、です。なので、
storeから取り出した配列を直接いじってる部分がないか
と言う方針で調査を進めました。そして見つけました。
lodash(JSライブラリ)の
_.remove()
メソッド※removeメソッドについてはこちらの記事がとても参考になります。
この処理の前後のstoreの値を確認し、確信しました。
この処理周りを改善し、無事バグ解決。
参照型とは
超ざっくり言うと、値が置いてある場所、のこと。
Java習いたてでよく注意点として出て来ます。ありがちな事象は以下
↓
ある変数を別の変数にコピーして、値2個できたやん、とか思って片方を変更する。
でも参照型の場合は実際には場所を指しているので、コピーされたのは場所情報だけ、変更されたのはその場所にある値である。
つまり同じ場所を指しているもう一方の変数も、一緒に値が変わってしまう。文面で起こすの辛いので実例↓
// JSの場合 var a = [1,2,3,4,5]; // 配列定義。 var b = a; // 変数をコピー。実際は配列のある場所だけコピーされる。 b.pop(); // bの末尾削除 console.log(a); // [1,2,3,4] console.log(b); // [1,2,3,4] // aも削除されちゃったまとめ
配列が参照型、と言うのは実際にその類のバグに遭遇しないと意識しないと思うので、
体験談を書き記してみました。これがあってから改めて意識するようになったのが、
- Vuexのstoreの中身がcommit以外から変更されるパターンもある(ReactのReduxなどでも同様だと思う)
- storeなど固定値として保持されている配列を直接いじらない
- 配列の中身に関するバグがあったら、直接操作を行っていないかを疑う
です。
ちなみにどうしてもいじる必要がある場合は、
例えばlodashの_.cloneDeep()
と言うメソッドを使うことで、
配列を完全複製し、それを使用する方法などが回避策になるかなと思います。この記事を見て、
うわ、こんなバグもありえるのか!、と感心していただけたり、
自分もあったわw、と共感していただける人がいたら幸いです。参考
- 投稿日:2020-12-27T10:49:09+09:00
[=LOVE]青春"サブリミナル"を再現してみた
アイドルグループ「=LOVE」(イコールラブ、通称イコラブ)さんの8thシングル『青春"サブリミナル"』の歌詞の一部をGitとJavaScriptを使って再現してみました!
手順
gitリポジトリ内で行います。
jsファイルを設置
unkown_by_ut.jsconst LOVE = 'love'; let answer二行目末尾に改行を入れておくのがポイントです。
一つ目のコミット
git add . git commit -m "さっきまで"jsファイルに変更を加える
unkown_by_ut.jsconst LOVE = 'love'; let answer =LOVE二つ目のコミット
git add . git commit -m "その答え"完成!
git logを実行すると、
commit 12fb9840578f2410882ea0e1fa66ac832319d093 (HEAD -> master) Author: user <user@sample.com> Date: Sun Dec 27 10:00:00 2020 +0900 その答え commit 2755bace9774959e9ef437c5db06e636ccd94a5a Author: user <user@sample.com> Date: Sun Dec 27 10:00:00 2020 +0900 さっきまでさらに
git diff 2755bace9774959e9ef437c5db06e636ccd94a5a 12fb9840578f2410882ea0e1fa66ac832319d093を実行して、
diff --git a/unkown_by_ut.js b/unkown_by_ut.js index 6966efa..90b7c6d 100644 --- a/unkown_by_ut.js +++ b/unkown_by_ut.js @@ -1,2 +1,3 @@ const LOVE = 'love'; let answer +=LOVE \ No newline at end of file差分が「=LOVE」となります。
まとめ
と、いうわけで!
さっきまでと違うもの〜♪ その答えは「=LOVE」~♪
『青春"サブリミナル"』名曲なので、よかったら聴いて下さい!!あと、ネタ被りを恐れてQiita内で「イコラブ」を検索したところ、
Twitterのいいね数を推定してみる
Twitterのいいね数推定の精度向上を図ってみる
という真っ当な記事を書いている方がいらっしゃいました。私も大場花菜ちゃん推しです。では、お粗末様でした〜
- 投稿日:2020-12-27T09:29:33+09:00
[個人開発]経験を共有するWebアプリ作ってみた!
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーは紫を選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。なぜつくったか
人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。
今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/あと、bootstrapは使ってません。
サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:29:33+09:00
人生経験を共有するコミュニティサイト作ってみた! & サービスの考え方
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:29:33+09:00
[個人開発]人生経験を共有するコミュニティサイト作ってみた!
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーは紫を選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。なぜつくったか
人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。
今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/あと、bootstrapは使ってません。
サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T07:10:10+09:00
【JavaScript】getElementById と getElementsByClassNameの違い
- 投稿日:2020-12-27T00:19:25+09:00
【解決!】Vue-Cliをインストール...できない!
状況
・Vue-Cliを使った本格的なアプリ開発をするためにVue-Cliをインストールしようとした
・過去にもVue-Cliをインストールして使った経験あり!
・コマンドプロンプトを開いて「いざ!やるぞ!」と思っていた矢先、早速出鼻をくじかれた...という話です。起こったこと①
・コマンドプロンプトで下のようにVue-Cliをインストール
npm -g install vue-cli・以下エラーが発生
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen) npm WARN deprecated har-validator@5.1.5: this library is no longer supported npm ERR! code EEXIST npm ERR! path C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue npm ERR! dest C:\Program Files (x86)\Nodist\bin\*vue.cmd* npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' ->'C:\Program Files (x86)\Nodist\bin\vue.cmd' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue.cmd npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Owner\AppData\Roaming\npm-cache\_logs\2020-12-24T15_55_11_169Z-debug.log対策①
ポイントは5行目~11行目。
要約すると
「既にインストールしているデータがある時のエラーだよ!」(5行目)
「具体的にはProgram Files (x86)\Nodist\bin\vue.cmd
のことだよ!」(8~9行目)
「このfileを消してもう一回やってみて!」(10行目)
とある。
・冒頭書いた通り、一度Vue-Cliはインストールしたことあるので、その時インストールしたファイルたちが残っていた。
どうもそのファイルが今回のインストールを邪魔している、らしい。
・なので、一旦Program Files (x86)\Nodist\bin
にあるvue.cmd
を消して再度npm -g install vue-cli
を実行起こったこと②
・開発へ進める!と思ったら、またしても以下エラー発生
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen) npm WARN deprecated har-validator@5.1.5: this library is no longer supported npm ERR! code EEXIST npm ERR! path C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue npm ERR! dest C:\Program Files (x86)\Nodist\bin\vue npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' -> 'C:\Program Files (x86)\Nodist\bin\*vue*' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly.・さっきと同じようなエラー。よくよく見ると...
npm ERR! EEXIST: file already exists, cmd shim 'C:\Program Files (x86)\Nodist\bin\node_modules\vue-cli\bin\vue' -> 'C:\Program Files (x86)\Nodist\bin\vue' npm ERR! File exists: C:\Program Files (x86)\Nodist\bin\vue・消すべきファイルの名前が変わっている。
対策②
・なるほど。過去インストールしたいくつかのファイルが邪魔して今回インストールできないわけだ、と悟り/同じく今回もvueファイルを消す。
・結局、「消す⇒npm -g install vue-cli
実行⇒エラー(○○を消してね!)⇒消す⇒...」を10回ほど繰り返した
○○に指定されて消したファイルは以下の通り
・こんなに何回もエラーを頻発した理由は、これらのファイルたちはnpm -g install vue-cli
を実行するとまた最新verが生まれてくるということ。
で、その生まれたファイルたちがエラーの原因となってしまうこともあった。
・結論、上図のファイルたちを一気に消してnpm -g install vue-cli
で正常にインストール完了!エラーの原因
・今回のエラーの原因はどうも先ほどお見せしたファイルたちのインストールした日時らしい。
・元々インストールしたファイルたちは2020/12/20にインストールしたモノだったので、これがある限りエラーを発生しまくった。
・そこで上記のようにファイルたちを一気に消してnpm -g install vue-cli
を実行し最新版のファイルが作成され、うまくいった!という流れ。最後に
大したことではないですが、ググって同じようなエラーコード出ている方々はいらっしゃいましたが、ほとんどの方はMacユーザーの方でした。
そういった方の対策案を参考にした自分はこのエラーも出していました。ここで初めてWindowユーザーである自分は"sudo"や"rm"などのLinuxが使えない、ということを学びました。
参考までに。