続・JavaScript 再入門

一応、一通り読んだ。

www.amazon.co.jp

JavaScript、自分で考えていたよりいろいろな書き方ができる。

それが故に、洗練されたものをつくるためには、「良いパーツ」を選んで使う必要がありそうだ。

今回はJavaScriptのメインともいえる、関数に触れてみる。

関数はオブジェクト

JavaScriptの関数は、オブジェクトである。複数の名前(識別子)と値を持つことができる。

関数の定義方法として以下の2つの書き方があるが、

function add(a, b) {
    return a + b;
};
var add = function (a, b) {
    return a + b;
};

関数がオブジェクトであることを意識できるので、後者の書き方がベターである。

関数、4つの呼び出しパターン

関数は、呼び出される際に、2つのパラメータ、thisarguments を自動的に受け取る。

但し、this に関しては、関数の呼び出され方によってセットされる値が異なる。

メソッド呼び出しパターン

あるオブジェクトのプロパティとして関数を定義した場合、メソッドと呼ぶ。

var someObject = {
    value : 0,

    add : function (someNumber) {
        this.value += typeof someNumber === 'number' ? someNumber : 1;
    }

};

someObject.add();
console.log(someObject.value);  // 1


someObject.add(2);
console.log(someObject.value);  // 3

この場合、this は someObject そのものが渡される。

関数呼び出しパターン

関数をオブジェクト内部に定義しなかった場合、JavaScript唯一のオブジェクト、グローバルオブジェクトのプロパティとなる。

このパターンを関数呼び出し、と書籍では定義してある。

var add = function (a, b) {
    return a + b;
};

var sum = add(3, 4);  // sum は7

この場合、add から見た this は グローバルオブジェクト そのものとなる。

コンストラクタ呼び出しパターン

new をつけて呼び出すことを前提としたパターン。

// コンストラクタ関数
var Stat = function (string) {
    this.status = string
};

// get_status というパブリックメソッドを
// Stat のすべてのインスタンスで利用可能とする
Stat.prototype.getStatus = function () {
    return this.status;
};

var myStat = new Stat("confused");


console.log(myStat.getStatus());  // confused

この場合、new で作成されたインスタンスそのものが、this にセットされる。

コンストラクタ関数は、new をつけて呼び出す前提なので、慣例として大文字始まりにすることが多い。

apply呼び出しパターン

JavaScriptにもともと備わっているapplyメソッドで、関数を呼び出せる。

var add = function (a, b) {
    return a + b;
};

var array = [3, 4];

var sum = add.apply(null, array);  // sum は 7

// status をメンバに持つオブジェクトを作成
var statusObject = {
    status : "OK"
};

// 先ほどのコンストラクタ関数呼び出しパターンで定義した、Stat.prototype を statusObject で呼び出す

console.log(Stat.prototype.getStatus.apply(statusObject);  // OK

applyメソッドは、第一引数にthisにセットしたいオブジェクト、第二引数に呼び出す関数の引数を渡せる。

継承していないはずのprototypeのメソッドさえ呼び出せる。

いろいろできるけど

大きな機能を書くときには、メソッド呼び出しパターンがいいことはいうまでもない。今回触れていないが、名前空間的なこともこれで実現可能だ。

ライトに試す場合は、関数呼び出しパターンで十分。でもすぐリファクタしたくなる可能性あり。

apply呼び出しパターンは・・・使い時が分からない。

コンストラクタ呼び出しパターンは、今回読んだ書籍では推奨されていない!何故 new がダメなのか、次回見ていきたい。

Rundeck との闘争

ウチの社では、Rundeck をジョブ管理サーバーとして使用している。

各バッチサーバー上のバッチプログラムを、定周期で起動させるのが仕事なのだが

何故かRundeckを運用するサーバーの負荷が右肩上がりで、しかも定期的にCPUが高止まりする、という困った状態に。

これが何とか解消できた、という話。

そもそもRundeckとは

rundeck.org

ウチらが取ってる構成(現状)

以下のような感じ。

f:id:ndx:20160212212525p:plain

  • バックエンドDBをデフォルトのH2 DatabaseからMySQLに変更
    • これやらないと、WebのGUIがとても表示が遅く使い物にならなかった・・・
  • 待機系によるバックアップ
    • Rundeck待機機に定義ファイル等を定期的にrsync
    • MySQLもスレーブ機投入

そしてMySQLが過負荷に

ただジョブを定期的に起動させるだけなのだが・・・典型的にヤバい感じに。

f:id:ndx:20160212214430p:plain

グラフを見ればわかるのだが、負荷が落ち着く期間もあるものの、傾向的には右肩上がり。

ジョブは総数70もないので、今後が思いやられていた。

slow.log を見てみると

こんな感じのが大量に出ていた。(これに早く気付いていれば。)

select commands0_.workflow_commands_id as workflow1_15_0_, commands0_.workflow_step_id as workflow2_17_0_, commands0_.commands_idx as commands3_0_, workflowst1_.id as id1_16_1_, workflowst1_.version as version2_16_1_, workflowst1_.description as descript3_16_1_, workflowst1_.error_handler_id as error_ha4_16_1_, workflowst1_.keepgoing_on_success as keepgoin5_16_1_, workflowst1_.adhoc_execution as adhoc_ex7_16_1_, workflowst1_.adhoc_filepath as adhoc_fi8_16_1_, workflowst1_.adhoc_local_string as adhoc_lo9_16_1_, workflowst1_.adhoc_remote_string as adhoc_r10_16_1_, workflowst1_.arg_string as arg_str11_16_1_, workflowst1_.file_extension as file_ex12_16_1_, workflowst1_.interpreter_args_quoted as interpr13_16_1_, workflowst1_.script_interpreter as script_14_16_1_, workflowst1_.json_data as json_da15_16_1_, workflowst1_.node_step as node_st16_16_1_, workflowst1_.type as type17_16_1_, workflowst1_.job_group as job_gro18_16_1_, workflowst1_.job_name as job_nam19_16_1_, workflowst1_.node_filter as node_fi20_16_1_, workflowst1_.node_keepgoing as node_ke21_16_1_, workflowst1_.node_rank_attribute as node_ra22_16_1_, workflowst1_.node_rank_order_ascending as node_ra23_16_1_, workflowst1_.node_threadcount as node_th24_16_1_, workflowst1_.class as class6_16_1_ from workflow_workflow_step commands0_ inner join workflow_step workflowst1_ on commands0_.workflow_step_id=workflowst1_.id where commands0_.workflow_commands_id=2061677;

workflow_workflow_step なるテーブルの定義を見てみると

| workflow_workflow_step | CREATE TABLE `workflow_workflow_step` (
  `workflow_commands_id` bigint(20) DEFAULT NULL,
  `workflow_step_id` bigint(20) DEFAULT NULL,
  `commands_idx` int(11) DEFAULT NULL,
  KEY `FK_9pkey6k5fdo6worgquakkh7d1` (`workflow_step_id`),
  CONSTRAINT `FK_9pkey6k5fdo6worgquakkh7d1` FOREIGN KEY (`workflow_step_id`) REFERENCES `workflow_step` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=sjis |

indexらしきものがない!(PKさえない!)

explain とってみると、案の定。

> explain select commands0_.workflow_commands_id as workflow1_15_0_, commands0_.workflow_step_id as workflow2_17_0_, commands0_.commands_idx as commands3_0_, workflowst1_.id as id1_16_1_, workflowst1_.version as version2_16_1_, workflowst1_.description as descript3_16_1_, workflowst1_.error_handler_id as error_ha4_16_1_, workflowst1_.keepgoing_on_success as keepgoin5_16_1_, workflowst1_.adhoc_execution as adhoc_ex7_16_1_, workflowst1_.adhoc_filepath as adhoc_fi8_16_1_, workflowst1_.adhoc_local_string as adhoc_lo9_16_1_, workflowst1_.adhoc_remote_string as adhoc_r10_16_1_, workflowst1_.arg_string as arg_str11_16_1_, workflowst1_.file_extension as file_ex12_16_1_, workflowst1_.interpreter_args_quoted as interpr13_16_1_, workflowst1_.script_interpreter as script_14_16_1_, workflowst1_.json_data as json_da15_16_1_, workflowst1_.node_step as node_st16_16_1_, workflowst1_.type as type17_16_1_, workflowst1_.job_group as job_gro18_16_1_, workflowst1_.job_name as job_nam19_16_1_, workflowst1_.node_filter as node_fi20_16_1_, workflowst1_.node_keepgoing as node_ke21_16_1_, workflowst1_.node_rank_attribute as node_ra22_16_1_, workflowst1_.node_rank_order_ascending as node_ra23_16_1_, workflowst1_.node_threadcount as node_th24_16_1_, workflowst1_.class as class6_16_1_ from workflow_workflow_step commands0_ inner join workflow_step workflowst1_ on commands0_.workflow_step_id=workflowst1_.id where commands0_.workflow_commands_id=2061677;
+----+-------------+--------------+------+------------------------------+------------------------------+---------+-------------------------+---------+-------------+
| id | select_type | table        | type | possible_keys                | key                          | key_len | ref                     | rows    | Extra       |
+----+-------------+--------------+------+------------------------------+------------------------------+---------+-------------------------+---------+-------------+
|  1 | SIMPLE      | workflowst1_ | ALL  | PRIMARY                      | NULL                         | NULL    | NULL                    | 2008680 |             |
|  1 | SIMPLE      | commands0_   | ref  | FK_9pkey6k5fdo6worgquakkh7d1 | FK_9pkey6k5fdo6worgquakkh7d1 | 9       | rundeck.workflowst1_.id |       1 | Using where |
+----+-------------+--------------+------+------------------------------+------------------------------+---------+-------------------------+---------+-------------+

index を張ってみる

> ALTER TABLE workflow_workflow_step ADD INDEX workflow_commands_id(workflow_commands_id);

張った直後のリソース

f:id:ndx:20160212225524p:plain

f:id:ndx:20160212225542p:plain

劇的に収まったようだ。。。ε-(´。`;)ホッ

後は、ジョブが集中する月初、0時0分0秒の状態を見て問題なければこれで良さそう。

JavaScript 再入門

技術ブログを書いてみようという試み。

ブログを書くのも初めてなのに、技術ブログ。何をしたものか。

何をしてもいいみたいなので、最初に触った言語、かつこの業界に入るきっかけとなった

JavaScriptに再入門してみようと思う。

ちなみに

仕事でJavaScriptをメインで使っていたのは14年前くらい、証券系のWebページ作成で活用していた。

いまだに某証券取引所のページで、現役で動いているものもあり

1年に1回くらい訪問して、健在っぷりを確認してホッとする反面

大丈夫なのだろうかという思いにとらわれている( *´艸`)

書籍選びなど

おもむろに「JavaScript」でググって見つけた以下のページ↓

postd.cc

今さら優秀なJavaScriptの開発者を目指すわけでもないが、再入門の手掛かりにしてみようと読み進める。

ブログ記事で学習するな、本を読め、ということなので、1冊買ってみる。

www.amazon.co.jp

古い本だが、確かに良さそうだ。

リファレンス本はいくつか見てきたが、この手の本は読んだことがなかった。

==!= は使うな

いきなりだが、演算子について。

値の調査によく使っていた演算子==!= だが、JavaScriptにおいては悪のようだ。

' ' == 0    // false
0 == ' '    // true
0 == '0'    // true

もちろん全部期待はfalseだろうが、この一貫性のなさはなんだろうか。

解説によると、比較する2つのオペランドが異なる変数型であった場合、値を強制変換してしまうとのこと。

JavaScriptは型に関して緩い印象があるが、こんなところに影響があるとは。

  • 解決策
    • == の代わりに === を使う。
    • != の代わりに !== を使う。

なんでリファレンス本はこんなことも書いていなかったのだろうか。。。

VB.NETで、And は使わず AndAlso を、Or は使わず OrElse を使うべき、ということを知ったとき以来の演算子ネタ。

レビュー時に ==!= を見かけたら今後は全部NGにしよう。

数値あれこれ

小数計算に向かない

JavaScriptには数値型が1つしかない。64ビットの浮動小数、要するにdoubleのみ。

1 === 1.0    // true

楽な時もある。

0.1 + 0,2    // 0.30000000000000004

JavaScriptに小数計算やらせないほうがいいね。やるなら一旦整数に。王道。

parseInt関数
parseInt("16")    // 16
parseInt("16 hoge")    // 16

これは有名。できるところまで頑張って数値にする関数。

parseInt("08")    // 0
parseInt("09")    // 0

0になるって!※

最初の文字が「0」の場合、8進数とみなすようだ。

parseInt("08", 10)    // 8

第二引数で基数を与えると安定。

Google Chrome だと、parseInt("08") -> 8 と出た。ブラウザ実装にもよるらしい。基数指定した方が幸せになれそう。

NaN

Not a Number の略として有名。

typeof NaN === 'number'    // true

型は数値型と主張している。

NaN === NaN    // false
NaN !== NaN    // true

一体どういうことやねん。

NaNを調べる方法としては以下を行うしかないようだ。

isNaN(NaN)     // true
isNaN(0)       // false
isNaN('hoge')  // true
isNaN('0')     // false

4行目、嫌な人も多いかもしれない。

一旦これまで

書籍をせっかく買ったので、読破してみます。

リハビリ終わったら流行りのライブラリとか行ってみます。