メモを揉め

お勉強の覚書。

プログラミングにおける略称のベストプラクティス(を誰か教えてください)

XML, DOM, JSON, APIなどの略称を変数の命名等で使う時のフォーマット統一したい(して欲しい)。

XMLHttpRequest

XML

Extensible Markup Language(エクステンシブル マークアップ ランゲージ)
ウィキペディア: Extensible Markup Language

Http

Hypertext Transfer Protocol(ハイパーテキスト・トランスファー・プロトコル、略称 HTTP)
ウィキペディア: Hypertext Transfer Protocol

Request

XMLだけ全部大文字、(略称)(略称)(単語)の組み合わせ。

DOMContentLoaded

そもそもイベントタイプって全部小文字やなかったんかいというツッコミを入れつつ。

DOM

Document Object Model (DOM)
ウィキペディア: Document Object Model

ContentLoaded

はいはいなるほど、頭文字の略称だけは全て大文字にするっていうパターンね、だんだん見えてきたよ。
組み合わせは(略称)(単語)(単語)。

jsonFlickerApi

flickrAPIJSONPで使うときに呼び出される関数の名前
なんと固定。
任意の名前を指定できない。

これは、メソッド名だから頭文字の略称はすべて小文字にするのか、ふむふむ。
Apiは略称だけど普通にキャメルケース。

toJSON

と思ったらそうでもないんだねえぇ〜、JSONは全部大文字なんだねえぇ〜。

こんな感じなので自分で命名する時も迷う。
ちゃんとした命名規則欲しい。

snake_caseだといいなと思ったけど、そういう問題じゃないっぽい。
railsにはActionModel::Serializers::Xmlというモジュールと、ActiveSupport::XmlMini_Nokogiri::Nokogiri::XMLというモジュールが存在する(Dashで見ただけですが)。
何か法則があるのかも知れないけど分からない。

個人的に略称は大文字か小文字どちらかに統一したいという欲求はある。 クラス、定数なら大文字、インスタンス、変数やメソッドなら小文字で全部書きたい。

結局どうするのがいいんでしょうね

みたいに書くのが一番規則性が保たれるような気がしている今日このごろ。

話題の五輪エンブレムをCSSで動かしてみた

今日もよく燃えてますね。

しかしそういった話は一切合切横に置かせてもらいまして、私はCSSで動かしたくなったので動かしてみることにします。

単純な図形とルール

このエンブレムは非常に単純な図形とルールで出来ています。

大抵のタイポグラフィは一貫するルールのような物を持ちつつ、それをあえてハズしてみたり、ちょっとズラしてみたりして、ある種の複雑さを持たせることで見る人の感覚を楽しませています。

一方、今回の五輪エンブレムはほぼハズしが無いです。
一部の文字を除いて3x3のマス目に、(相似形を除けば)たった3種類のパーツの組み合わせだけで文字を表現しています。
さらにその3種類のパーツも円と正方形のネガポジだけで表現しているので、出てくる図形は2種類だけ。
ある意味で受け取り手に干渉するスキマを残す、見る人に想像させる余地をあえて作る様なデザインと言えます。(だいぶ良く言った)

こういうミニマルなデザインもけっこう好きです。

プログラマブル

こういったデザインの特徴として自動生成するのが非常に容易だということが言えます。

今回の場合だと正方形と円だけなのでCSSでの表現にも向いてます。

アニメーションに関しても始点と終点の配置だけ指定すれば、あとはCSS3のtransitionに丸投げ出来ます。

ジェネレータ

ひと通り動かし終わったので、ついでにジェネレータも作りました。

しかしこのエンブレム、5年後も使われているのでしょうか。
それが心配。

setTimeoutの挙動について

out!

JavaScriptによるアニメーションの制御について調べていたところ、本筋から離れてしまいそうだったのでここに。

ここまでの流れをおおまかに書くと、

  • JavaScriptにはタスクのキューがあり、頭から順に登録されたタスクが処理される。
    ここで言うタスクとはほぼ関数と考えていい。
  • setTimeoutは指定時間後にそのキューにタスクを追加する。」
    という概念が多くの説明で使われているけど本当?と感じる様な挙動があった。
  • ブラウザによる画面の再描画はタスクとタスクの間にしか起こらない、
    タスク(関数)の実行中には再描画は起こらない。
  • 追加されるタスクは必ずキューの一番後ろに追加されるのか?
    イベントに紐付けられたタスク等の場合、割り込む事はあり得るのか?

このあたりのことが気になったので実験をしました、そしてその結果から仮説を立てました。

setTimeoutは指定時間後に本当にタスクをキューに登録してる?

再描画について調べていると、キューが空になったタイミングでとか、キューがアイドル状態になった時にといった表現が多い。
キューが空になるというのは登録されたタスクが全て処理され、キューに何もない状態のことだと思う。
アイドル状態も同じ表現だと思う。

では以下のコードではどうのようなことが起こっているのだろう。

for (var i = 0; i < 10; i++) {
    setTimeout(emptyFn, 0);
}

function emptyFn() {}

指定時間後にタスクをキューに追加しているという言葉をそのまま解釈すれば、0ミリ秒後に10個のタスクがキューに登録されることになる。
空のタスクなので追加されるやいなや一瞬で処理され、再描画の確認をすることは出来無い。

では次のコードの場合はどうなるだろう。

// 重い処理を10個連続で登録する
for (var i = 0; i < 10; i++) {
    setTimeout(heavyFn, 0);
}

var cnt = 0;
function heavyFn() {
    // 0.6〜0.8秒位かかる重い処理がここに書いてある...
    console.log(++cnt + ' done');
}

for文でタスクを10個追加している点は同じだが、そのタスクは0.6〜0.8秒ほど掛かる重い処理になっていて、最後に'done'と出力する。

documentのクリックイベントには'click'と出力する処理を登録しておく。

document.addEventListener('click', function() { console.log('click'); });

(実験ではこれに加えて視覚的に分かりやすいように、heavyFnにはdivのサイズを変える処理を、クリックイベントにはbody要素の色を変える処理を追加している。
これによりブラウザの再描画のタイミングも同時に観察する。
さらにheavyFnの1個目から10個目が終わるまでの間だけrequestAnimationFrameの呼び出しをカウントする。)

もし、指定時間後にキューにタスクが10個追加されて、クリックイベントよって発生したタスクもキューの一番最後に追加されるのであれば、setTimeoutよって登録されたheavyFnが全て終了してから、クリックにハンドルされたタスクが走ることになる。
上のコードの場合だと'done'が10回出力される前にクリックをしても、即座に'click'は出力されず、'done'が10回出力された後で'click'が出力されるはずだ。

ブラウザによる差異

実際に実験をしてみるとブラウザによって挙動が違った。
ChromeSafariでは、divが大きくなり始めてからクリックをすると直ぐにbodyの色が変化し、その後もdivは大きくなり続けた。
Firefoxdivのサイズが変化する間に再描画が起こらず、divのサイズが最大になった状態がbody要素の色の変化とともにまとめて再描画された。

この挙動は一体どのように考えればいいのだろうか?
ちなみに、ここから先の話は実装を見てきたわけでは無いので、あくまで説明上つじつまの合う仮説を立てている。

ChromeSafariの場合

Safariスクリーンショット

Safariのスクリーンショット

あくまでキューはキュー

10個のタスクがsetTimeout(task, 0)によって10回繰り返し登録された時、すぐさまキューにタスクが10個全て登録されるわけでは無い、という考え方。

setTimeoutがブラウザのタイマースレッドへ、
alert('D')0ミリ秒後にキューへ登録するよう、依頼します。
blog.mouten.info: JavaScriptのsetTimeoutを理解する

この記事の説明に出てくるタイマースレッドというものに一度積まれた後で0ミリ秒後にキューに追加といった処理を行っているとすると、必ず一つずつキューに追加していて、同時に10個のタスクがキューに放り込まれるようなことは無い、ということになる。

setInterval関数を実行したときに、「現在時刻+第2引数で指定した時間」の時刻をタスクに付けてキューに積みます。
時間が経ち、そのタスクがキューの先頭に来ると、Scriptエンジンはそのタスクを実行します。
風と宇宙とプログラム: JavaScriptのsetInterval関数の意味を正確に理解するための1つの説明

タイマースレッドに登録されたタスクは一つずつキューに追加され、そのタスクが終わると設定された時間が早いものから先に再びタイマースレッドからキューへタスクが送られる。

優先度付きキュー

もうひとつの考え方としては、クリックイベントによって発生したタスクがsetTimeoutよって登録されたタスクの間に割り込み優先的に実行された、という考え方。

タスクには時刻が書かれており、キューはその時刻順にソートされています。
ほとんどのタスクの時刻は「即時」を意味するような時刻が書かれていますが、タイマのようなタスクには特定の時刻が書かれています。
その時刻が現在時刻より未来のものは処理しないことになります。
風と宇宙とプログラム: JavaScriptのsetInterval関数の意味を正確に理解するための1つの説明

この考え方の場合、for文によって10個のタスクはすでにキューに登録されているが、時刻によってソートされるため、0ミリ秒後に実行と書かれたタスクよりも即時と書かれたクリックイベントが優先的に実行されたということになる。

Firefoxの場合

Firefoxスクリーンショット

Firefoxのスクリーンショット

Firefoxの場合setTimeout(task, 0)で登録された10個のタスクの間に再描画は起こらなかった、さらにクリックイベントの発火も10個のタスクが終わった後だ。

この挙動の場合、
0ミリ秒語に10個のタスクがキューに追加され、クリックイベントによって発生したタスクが一番最後に追加された
という考え方で問題無さそう。

まとめ

まとまらない。

でも、ほとんど場合この挙動の違いが問題になるような場面は無いという言い伝えがある。