ザリガニが見ていた...。ザリガニが見ていた...。読者になるザリガニが見ていた...。この広告は、90日以上更新していないブログに表示しています。2013-06-11注文金額はどのように集計されているのか?javascriptAmazonの注文履歴が過去から現在まですべて集計されてしまうという、あのブックマークレットは衝撃的であった。こんな風にブラウザの世界を自在に操作できるJavaScriptって素晴らしい。このブックマークレットがどんな仕組みで集計しているのか、未だすべては理解できていない。(特にDeferredとか)コードの流れ追跡しながら調べてみた。URL欄のコード改行なしだと読み難いので、セミコロンで改行を入れてみた。srcのURLは、フォークした自分のgistに変更している。})();URL欄に入力したjavascript:に続けたコードは、JavaScriptとして実行される。上記のコードは、現在のページのbodyタグ内にscriptタグを追加してくれるのだ。<body>...</body></html>仮に上記のようなHTMLソースだったとすると、JavaScript実行後は以下のようになるのだ。</body></html>つまり、src=に続くURLのaitter,jsが読み込まれて実行されるのだ。実際の金額の集計は、gist置かれたこのaitter,jsに委ねられている。gistのコードこちらはフォークしたgistコード。実行すると入力ダイアログなしで、いきなり注文履歴のすべての年間を集計する仕様。コメントも入れてみた。})();URLに貼り付けるjavascript:で始まるコードも、gistのaitter,jsも、括弧の連続技であるfunctionで囲まれている。これは即時関数と呼ばれる書き方だそうだが、その詳細は素晴らしい解説をしている以下のサイトに委ねる。三等兵つまり自分の理解したところでは、即時関数の中に書いたコードは、その外側のコード世界に影響を与えないのだ。ブックマークレットは、読み込まれた既存のページに付加されて実行されるJavaScriptコードである。既存のページでもJavaScriptが利用されていると、うっかりすると同じ関数名や変数名を使ってしまい、動作がおかしくなる可能性がある。そんな可能性を排除するために、即時関数というカプセルの中に処理コードを書いているのだ。(と思っている)その関数の定義と実行を両方行いたい時のJavaScriptお決まりの書き方なのだ。'2012';3行目、4行目で定義されているtotalとyearは、このブックマークレット内で共有される変数である。この即時関数の中であれば、どこに書いたコードからでも参照・変更できるのだ。totalは、year(西暦)をキーとして、西暦ごとの集計を保存しておく連想配列。init()は、オーバーレイ表示のCSS定義と、変数totalとyearの初期値を設定している。8〜20行目=オーバーレイ表示のCSS定義21〜22行目=注文時期の最も過去(最後)の西暦を取得して、それを変数yearに設定。23行目=連想配列totalを設定。過去の西暦が2006だとすると、total[2006]=0;が実行されるのだ。24行目=以上の初期設定が完了すると、集計処理のメインとなるmain関数を実行。load(num);main関数は、引数numに0が渡されて始まる。29行目でいきなりload(num)関数が呼ばれて、処理はload(num)関数に移る。get(num);55行目のload(num)関数の始まりは、謎の変数定義から始まる。$.Deferred();$.Deferred();とは何をしているのか?実はこの$.Deferred();を理解することで、このブックマークレット全体の流れが納得できる。次の56行目ではget(num)関数が実行されてしまう。よって、get(num)関数から詳細に追跡していく。}71行目のget(num)関数の始まりも、同じく謎の変数定義がある。$.Deferred();直前のload(num)とまったく同じコードである。$.Deferred()は何をしているのかと言えば、jQueryのdeferredオブジェクトを取得しているのだ。deferredオブジェクトは、非同期の処理の完了を待って実行する仕組みを提供してくれる。非同期なので$.ajaxの完了を待たずに、get(num)関数の最後の行まで処理が進んでしまう。そこで78行目で、deferredオブジェクトのdf.promise();を返している。df.promise()は、「処理が終わるまで待っていてね」という合図のオブジェクトだ。load()は待機するのだ。load()の処理が再開される。get(num);から処理が再開されるのだ。}df.resolve(data);は処理が正常に完了した合図なので、57行目からのpage.done()ブロックも実行される。page.done()ブロックでは、取得した注文履歴ページのHTMLから、クラス属性がpriceである金額を集計している。main(num)deferredオブジェクトのdf.resolve(_total);は、呼び出し元の.done()ブロックを実行する。.done()ブロックは、注文履歴のページが続く限り集計を繰り返す。main(num+1);そしてもう1つ、df.reject();は、呼び出し元の.failブロックを実行する。.failブロックは、現在の西暦になるまで、1年ずつ、年間集計を計算する。すべての西暦を集計し終えたら、alertダイアログで結果を出力している。}なるほど、なるほど。コードの流れがすべて理解できた。これを雛形に様々なページを集計できるのだ!(モロ屋さんに感謝!)参考ページ以下のページが大変参考になりました。読者になる広告を非表示にする関連記事2015-01-15RubyとC言語でもペントミノバズルを解いてみる前回からの続き。AppleScriptコード日記の容量の制限で溢れてしまったので、9月26日から分割した。...2010-01-25コマンドから引き出すGUIの機能OSXが素晴らしいGUI環境を提供してくれるのだから、わざわざコ...2010-01-14モニタを閉じてスリープ中のMacBookをリモート操作できる環境にするMacBookのモニタを閉じると普通はスリープする。読者になるこのブログについて検索リンク記事一覧はてなブログをはじめよう!zariganitoshさんは、はてなブログを使っています。あなたもはてなブログをはじめてみませんか?はてなブログをはじめる(無料)はてなブログとはザリガニが見ていた...。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。