コールバック関数でうまくthisが使えない問題
Javascriptで内部変数を保持できるClass的なものを実装しようとすると、クロージャやプロトタイプが使える。
クロージャの場合、内部で定義される関数(メソッド)がインスタンス生成される度に定義されてしまうのでパフォーマンスが良くない。
なので今回はプロトタイプを使って実装していた。そこで少しつまったこと。
function Person(name){ this.name = name; } Person.prototype.sayName = function(){ console.log("My name is ",this.name);// -> 'My name is Taro' } Person.prototype.delaySayName = function(){ window.setTimeout(function(){//コールバックとしての無名関数 console.log("My name is ",this.name);// -> 'undefined' }, 1000); } var taro = new Person('Taro'); taro.sayName(); taro.delaySayName();
このdelaySayNameのコールバック関数のthisはwindowを指している。
これは、関数内のthisが指すのはその関数を呼び出したオブジェクトであることに起因している。
イメージとしてはこんな感じ。
//ブラウザ上のjavascriptはグローバルオブジェクト(Window)上で動いている var obj = {name:'test'}; var sayThis = function() { console.log(this); }; obj.sayThis = sayThis;//objオブジェクトにsayThis関数を追加 obj.sayThis(); //objから呼ばれたsayThis関数のthisはobj sayThis(); //グローバルオブジェクト上のsayThis関数なのでthisはWindow
つまり、問題のコードは
Person.prototype.delaySayName = function(){ // ここのthisはPersonオブジェクト window.setTimeout(function(){ console.log("My name is ",this.name); //この無名関数はwindowのコールバック関数と呼ばれている //よってここのthisはwindowとなる(もちろんwindow.nameは存在しない) }, 1000); }
ではどうすればいいかというと、以下の感じ。
function Person(name){ this.name = name; } Person.prototype.sayName = function(){ console.log("My name is ",this.name); } Person.prototype.delaySayName = function(){ // ここのthisはPersonオブジェクト window.setTimeout(function(name){ console.log("My name is ",name); }, 1000, this.name); //第三引数でthis.nameを”値”として与える } var taro = new Person('Taro'); taro.sayName(); // -> 'My name is Taro' taro.delaySayName();// -> 'My name is Taro' taro.name = 'Jiro';
ただしこの場合、this.nameは値として渡るので、途中でnameがJiroになっても出力結果は変更されない。
参照(ポインタ)として渡したい場合、this.nameの参照をコールバック関数に渡す必要がある。
javascriptで参照渡しをしたい時、渡すものがオブジェクトだと勝手に参照が渡される(怖い)。
function Person(name){ this.name = name; } Person.prototype.sayName = function(){ console.log("My name is ",this.name); } Person.prototype.delaySayName = function(){ // ここのthisはPersonオブジェクト var self = this;//thisへの参照をselfに渡す window.setTimeout(function(name){ console.log("My name is ",self.name); }, 1000); //self(Personオブジェクト)はオブジェクトなので参照が渡る } var taro = new Person('Taro'); taro.sayName(); // -> 'My name is Taro' taro.delaySayName();// -> 'My name is Jiro' taro.name = 'Jiro';
答えをしればなるほどなぁって感じだった。
thisの指す先は開眼Javascriptの知識が役に立ったような気がしましたまる
参考:
setInterval() → this でひっかかった - Web系がおもしろい。
O'Reilly Japan - 開眼! JavaScript
ISUCON4の過去問をやる(1)
就活してて「ハッカソンでてるのでアイデアを形にするのが得意です。技術力は...」と言い淀むのがつらすぎたので、
前々からやってみたいと思っていたISUCONにでる決意を固めた。
(ISUCONはIikanji Speed Up CONtestというサーバチューニングコンテスト)
準備
ISUCONの過去問はAMIが公開されているが、偉大なるmatsuuさんがVagrantfileとDockerfileを用意してくれているので、
今回はそちらを利用させていただくことにした。
GitHub - matsuu/vagrant-isucon: ISUCON過去問を構築するためのVagrantfile集
GitHub - matsuu/docker-isucon: Dockerfile for isucon
最初使ったことのないVagrantを勉強がてら利用していたが、nginxのrpmが404だったりで所々手作業になってしまい、
なんとかWebアプリの起動までいったがメモしてなくて再現性がとれなかった。
なので最終的にイメージでバッコリ持ってこれるDocker版でやってみた。
Docker版ではReadmeに沿ってコマンド打てばシュッと立ち上がってくれてよかった。
score:949
Node版アプリの起動
既存のアプリはRubyなので、Nodeのアプリを立ち上げる。
https://gist.github.com/mirakui/e394ed543415852d34a6:ISUCON4 予選当日マニュアルにあるように、
ホスト側/etc/supervisor.confを書き換える。
その後、``sudo /etc/init.d/supervisord restart``だとinitプロセス(supervisord)をkillしてコンテナが落ちるので、
supervisorctl reload
をする。
ベンチマーカーの調査
$ tail -n +2 /tmp/isucon.node.log | awk '{ print $2 }' | sort | uniq -c 806 / 878 /images/isucon-bank.png 440 /login 74 /mypage 1 /report 878 /stylesheets/bootflat.min.css 878 /stylesheets/bootstrap.min.css 878 /stylesheets/isucon-bank.css
``/report``へのアクセスが1回しかさばけてない(?)。
とりあえず、以下の順序でやってみる。
- インデックスを貼ってみる(高速化 = インデックスという印象)
- 静的コンテンツをNode.jsに配信させない
- KVSとかmemcacheを使ってみる
インデックスを貼る
参考:漢(オトコ)のコンピュータ道: MySQLのEXPLAINを徹底解説!!
EXPLAIN句でインデックスが使われていないSQL(type=index OR type=ALL)を探す。
そこにインデックスを貼る。
score:1928
今後の方針
いろいろやっているがなかなか上手くいかない。
ISUCON初心者なのでしばらくはWriteup的なものを参考にしながら手を動かしていく。
次へつづく(10000点超えたら書く)
良い感じにHTTPS対応したexpress(Node.js)サーバを立てる
目標:
- Lets's Encryptで証明書の作成してHTTPS対応Node.jsサーバを立てる
- QUALYS SSL LABSでA+評価を目指す
HackDay2017に行った
2/4,5(土,日)でHackDayというYahoo!Japan主催のハッカソンに参加してきました。
hackday.jp
結果
学生部門で優勝できましたわーい #hackdayjp
— キンメモドキ (@kinmemodoki) 2017年2月5日
と軽い発言をしてたけど、驚きと興奮で手足が震えてうまく入力ができずこんなツイートになってしまった。
ちなみに、作ったものは「服の保温性をハンガー内の温度センサーで自動取得、その日の行き先に応じて上着をサジェストするIoTハンガー」みたいなもの。自分はサーバーサイドを担当してた。
当日まで
時は遡って開催3日前の水曜日、当初自分の提案したアイデアでは、「服の重さで保温性を自動測定してサジェスト」といった感じだった。重さでやろうとしていたのは、見に来てくれた人たちの上着を使って即時デモとして使えていいかなーという思惑があった(温度センサーだと情報取得に時間がかかる)。また方針としても、行き先の最高/最低気温から上着とインナーの複数サジェストしたり、サジェスト方法もただ光らせるだけというのが目標だった。ここから保温性の評価は温度センサーでやろうという意見がでていい感じにブラッシュアップされた。
アイデアはこんな感じでいこうという流れの中、前日の夜にターニングポイントとなるメッセージが投下された。
話は別ですが、何作るんですか?って質問された時に今のプラン答えても、GO飯ほどウケは良くないような感じがある(想像)のを改善すべきかどうか どうなんでしょう
*GO飯 : 前回HACK Uで最優秀賞を受賞したやつ
このメッセージを見て「あぁ...たしかに...もうだめだぁ...」という気持ちになっていた。なんとかウケるアイデアにしなければ...いろいろ考えたが何も浮かばず、夢の中でもアイデア考えて夜中4時に目が醒めたりした。
当日
競技開始後、とりあえずモックサーバーを立てるために簡単な設計として情報共有をした。
しかし、やはりツマラナイということでもう一度メンバーで話合い、やはりハンガーを動かすしかない...(ウケ狙い)ということになった。それに準じて複数の服サジェストも簡略化され上着1着だけ選出という感じに。
サーバーサイドではやることはあまりなくて、nodejsとexpressで開始12時間後くらいには完成した。内容としてはiOSクライアントGETのクエリで飛んできた行き先と時間を元にOpenWeatherMap APIを叩いて最高/最低気温の取得、ハンガーからの温度の管理と保温度のランク付け等々。。。
その頃(2/5 0時)、朝の仕様変更を受けて、ハード班が炎上していた。ハードのことは全くわからないので、ちょっとでも集中できるようノイズキャンセリング機能つきヘッドホン(MDR-1000X)を貸したりしていた。とりあえずハードのモックができた頃、モックの真似して配線ぐらいはできそうだったのでまかせてもらった。4年前の学部1年時代に実験で扱ったはずのブレッドボードは全く記憶になく、とにかくお手本を見ながら黙々と組み立てていった。やっている内容は全くわからなかったが、なんか電子工作しているみたいで楽しかった(錯覚)。また、モーターのギアボックスも組み立てたりしていた。小学生の頃そば屋のプラモデルを作ったのを思い出した。楽しかった(小並感)。
いよいよやることがなくなったのでハンガーのカバーとしてロゴのとーきちろー君を画用紙で作ることにした。正直自分は回路むき出しの無骨な感じが好きで渋々やっていたが、最終的に「サルが可愛い」みたいなことを言ってもらえてよかったらしい。ちなみにこれの材料を近くのドンキーホーテに買いに行ったが、閉店が早朝5時だったらしく、あと10分買い出しが遅かったらあの可愛いサルは実現されなかった。あぶない。なお、閉店間際だったので焦って画用紙を(30枚*)3セットも買ってしまい、自宅に80枚以上の画用紙が残っている。やってしまった。
とーきちろーカバーの1つ目が完成した朝6時、ついにカフェインが切れて1時間弱仮眠を取った。起きた頃にはカフェインの離脱症状で気分が悪くしばらく休んでいたので、実質2時間ほど休憩していた。8時頃にはYahoo!のスタッフの方から支給された果物とセブンイレブン?のパンを食べて回復した。あとはとーきちろーカバーの残りを作ったり、サーバーのバグ取り、プレゼン担当の練習付き合い、ハード班の応援をしたりしていた。最後の応援は確実に必要なかった。
発表
開発終了の12時、ハード班の健闘もあってなんとかハードは2つ完成していた。残り2つも回路は組んであったがなぜかサーバにGETリクエストを送信できていなかった。(あとから調査した結果、どうやら電源の電池(マンガン)が悪かったらしい。)
そして発表、プレゼン担当がいい感じのプレゼンをしていた。そしていよいよデモのタイミング...!
「18時に沖縄で仕事!」
ここで分厚いダウンコートのハンガーが動き、真ん中に涼しめのセーターが残る予定だった。
(シーン...)
発表が90秒で打ち切りのためか約3秒の沈黙が無限に感じた。そしてプレゼン担当が諦めて説明に戻った直後
ウィンウィンウィンウィン...
かなり怪しい音を立ててダウンコートのハンガーが動いた。その時、審査委員長の村上さんがとても笑っていたのを今でも鮮明に覚えている。僕達が狙っていた笑いだった。最高。
その後、いろいろあって気がついたら学生部門最優秀賞をもらっていた。
感想
一般参加チームの作品が24時間制作と思えないほどのクオリティで驚いた。やはり会社で開発をしている人たちはフレームワークやデザインパターンの知識があって実装が早くクオリティも高い、という印象だった。問題定義からその解決コンセプトまでとてもスマートなものが多く、技術も面白くて、これが金をもらって働くエンジニア/デザイナーの仕事か...!!という気持ち。
また、Yahooの会場サポートもとても良かった。コーヒーやお菓子が無限に食べれるので開発効率も爆上げだった。良い。
どうでもいいけど、強そうなエンジニアはペルソナ2とかにでてきそうな服装や髪型でかっこよかった。
自分たちの開発に関しては、やはり今回もハード班に負荷をかけすぎた印象。やはり自分も電気工作を始めるしかないか...!!まずはスピーカーから...
他チームの作品について
ゲーミフィケーションを取り入れた作品があってとてもおもしろかった。特に、[55 たべとるモン]が好きで、食品栄養価をキャラクタライズすることで食育できるのはとても楽しそうで良いなと思った。日本は食事の写真を撮るのが大好きなので、かなり上手いUIだな〜という気持ちだった。
あとは各優秀賞以上のチームは技術だけでなくアイデアも洗練されていた。特に「RecipeMix」と「いらすとか」がすごい。
最後に
チームのみんな、HackDayの運営の皆様、おもしろい作品を作っていたすべての参加者の皆様、そして観てくれた視聴者の皆様、どうもありがとうございました。また何か開発する機会でもよろしくおねがいします。
ウチのチームではHackDayの日記を書くのが流行っているそうです。
Open Hack Day 2017に参加した話 - いまにいたる
HackDay 2017 に出場して受賞してきた話 #hackdayjp - kdenologue
git challenge 2017.01.28 に行ってきた
git challengeはmixi社が開催しているGitにまつわる様々なトラブルを解決しよう!みたいな大会で、その第5回目に参加させてもらった。正直「Git、アド、コミット、クローン、プッシュ、リセットできる」みたいな原始人開発しかしていないのでGitは全然使えてなかったが、予習すればなんとかなるかな〜ぐらいな気持ちで応募した。
mixi-recruit.snar.jp
競技当日より前
一応競技なのでなんとか競えるようにがんばるぞ〜とおもって公開されている過去問で予習したりしていた。あとはzshのailiasとかpecoを使ってシュッと操作できるようにいろいろ準備してた。
参照 : peco と alias -g で git に便利革命おきた - Qiita
結果
gitchallenge惨敗太郎でした
— キンメモドキ (@kinmemodoki) 2017年1月28日
悲しいなぁ
問題の本質じゃなくてgitの基礎知識不足で悩んでいた節があった。
特に深刻だったのがgitの仕様の認識不足だった。競技当日まで「gitは差分を保存してバージョン管理をしている」みたいな認識でいて、[commitID]はその差分ファイルを指していると思っていた。(おそらくgit log -pとかの表示を見て勘違いしていた)
なので競技中は焦って「git diff [commit id] [commit id]」とかも「差分と差分のdiff(差分)」ってどういうことだ?みたいな感じで混乱していた。そんな感じでコンフリクトも上手く解消できなくて、ぐぬぬ...といった感じだった。
翌日
とりあえず当日は「知っていても使えない」ということがわかったので、前述の勘違いを正したり、うまく理解できてないものは解けるまでやってみたりした(最後の問題はちょっと厳しい...)。
採点できず、なんとな〜くわかった感が漂った程度だけど、参加当日以前よりはるかに理解できていると思う。
感想
予習でもデモリポジトリで実際に操作して理解しているつもりだったが、やっぱり一人でやるのには限界があるのでとにかく参加できてよかったなぁという気持ちです。一日で終わるイベントなので、当日できなかった悔しみを復習に回せるのも良い感じでした。(本当はもうちょっと競技内でやっていたかったけど...)
最後に、相方の4geruくん、チューターやスタッフの方々、懇談会で話をしてくれた皆様、とても楽しくてよかったです。どうもありがとうございました。
余談
mixiといえばエンジニアがクルーズ&アトラスで開発していることで有名ですが(?)、git challengeでもいい感じのイスに座らせていただけました👏👏👏👏👏👏
grepでURLを検索(正規表現)
URLっぽい文字列を検索
index.htmlは適当に変えてください.
# grep -Eo "http(s?)://(\w|:|%|#|\$|&|\?|\(|\)|~|\.|=|\+|\-|/)+" index.html
ヒット例
http://www.slideshare.net/kinmemodoki http://kinmemodoki.hatenablog.com/ https://hacku.kinmemodoki.net https://fonts.googleapis.com/css?family=Open+Sans:300
htmlのhref/src属性のURLだけ欲しい場合
# grep -Eo "(?i)(href|src)\s*=\s*(\"|')http(s?)://(\w|:|%|#|\$|&|\?|\(|\)|~|\.|=|\+|\-|/)+(\"|')" index.html
wgetでwebクローリングするときのメモ
http://www.bookshelf.jp/texi/wget/wget-ja_2.htmlを見る限り,
wgetを一回のコマンドでは同一ドメインのページは再帰的に(深度制限なしで)収集しつつ,外部ドメインは参照されるスクリプトのみ収集するのはできないっぽい.
落としてきたファイルに-i file -F
オプションで再帰的に読み込めば,うまくいきそうだと思った.
指定したページのドメインが配信するコンテンツのみ保存するコマンド
wget -r -l inf --convert-links -nc kinmemodoki.net
この場合,kinmemodoki.netドメインにあるwebページを再帰的にDLしてくれる.
しかし,外部コンテンツのjqueryやwebフォントが保存されないため,一部表示が乱れる.
指定したページとその関連コンテンツを保存するコマンド
wget -r -l 1 -H --convert-links -nc kinmemodoki.net
この場合,kinmemodoki.net/index.htmlのページのみ完璧にレンダリングできる.
しかし,深度2以上の内部コンテンツ(/content/a.htmlなど)がDLできない.
-l inf
とかにすると外部コンテンツのリンクも無限に辿ってしまう.
同一ドメインのコンテンツに対するレスポンスヘッダ表示
(死活監視,改ざん検知とかにつかえそう)
wget -m -np -S --spider kinmemodoki.net
なんか役立ちそうなwgetオプションたち
参照:http://www.bookshelf.jp/texi/wget/wget-ja_2.html
クロールの挙動関連
オプション | 説明 |
---|---|
-r | 再起的にリンクを辿る(html/xhtml形式のhref/src属性を参照する) |
-l (depth) | (depth)回リンクを辿る.-l inf で無限に辿る. |
-H | ホストをまたいで辿る. デフォルトでは起点URLと同じドメイン(サブドメイン含む)を辿る. |
-T (seconds) | タイムアウトを設定する.DNS,接続,読み込み待ち,を一律で設定する. デフォルトは読み込み待ちの900秒のみ. |
-np | 親ディレクトリは辿らない. ( example.com/web/index.html が起点ならexample.com/ は辿らない) |
-nc | すでに巡回した同一パスのファイルには,ローカルに保存したものを参照する. 動的に変化する場合は指定しない方が良い(?) |
–random-wait | リクエスト毎に0.5s-1.5sのウェイトを入れる. |
ファイルのDL関連
オプション | 説明 |
---|---|
-k | ファイル内の相対パスを,ローカル内でも参照できる様に変換./foo/doc.html 内の /bar/img.gif を, ../bar/img.gif にする. |
-S | レスポンスヘッダを出力する.コンテンツに付与したい場合は-s . |
-N | タイムスタンプを確認する. 以前の実行から更新されていないファイルはDLしない. |
-E | ファイル名がhtmlでないとき,接尾子`.html'を付与する. |
-O (file) | レスポンスを全て同一ファイルとして(file)に出力. |
-nd | ディレクトリの階層をつくらない. 複数回現れるファイル名は .n の接尾子がつく. |
-spider | ファイルをダウンロードしてこない |
--restrict-file-names=unix | OSでファイル名にできない文字をエスケープする.windowsは–restrict-file-names=windows にする. |
--convert-links | リンクがローカル上でも参照できるように変換する. |
-m | -r -N -l inf --no-remove-listing(FTP関連のオプション) と同じ. |