Hatena::Groupptech

ぷちてく RSSフィード

Archive
 
ProfileProfile

2017-04-01

Hatena::Letの後継作り

05:14

いよいよボロい。誰か後継作らないかなと数年ボーッとしてる間に Heroku の 24/7 が死んだので、Google Cloud とか Azure みたいな無料系で回していく感じにしたい。

みんな大好き node.js や、RubyPython 辺りが人集まりやすそうと思ってる。

トラックバック - http://ptech.g.hatena.ne.jp/noromanba/20170401

2017-03-05

element.click() が効かない時

04:17

ハマりそうなやつ。元記事はいわゆる Callback Hell 系の文脈

検証コードで安直に .click() したら効かなかった。

body = window.document.body;
body.onclick = () => {
  console.log('outer');
  body.onclick = () => {
    console.log('inner');
  };
  body.click();
};
body.click();
// -> outer
http://ptech.g.hatena.ne.jp/noromanba/20170302/1488491168#element-click-failed

内側 .click() 動かない。

回避策

a-kuma3

.dispatchEvent(MouseEvent) だと、内側も発火した >Firefox

const do_click = (e) => {
  const clickEvent = new MouseEvent("click", {
    view: window,
 });
 e.dispatchEvent(clickEvent);
};

body = window.document.body;
body.onclick = () => {
  console.log('outer');
  body.onclick = () => {
    console.log('inner');
  };
  do_click(body);
};
do_click(body);

<snip>

.click()setTimeout() でずらしても、発火した。

setTimeout(() => body.click(), 0)
http://ptech.g.hatena.ne.jp/noromanba/20170302#c1488502400

確かに両方返ってくる。

// -> outer
// -> inner

手元で試した setTimeout 版。

body = window.document.body;
body.onclick = () => {
  console.log('outer');
  body.onclick = () => {
    console.log('inner');
  };
  setTimeout(() => body.click(), 0);
};
body.click();
// -> outer
// -> undefined
// -> inner

これも両方動く。

感想

noromanba

> a-kuma3

検証 thx です。.dispatchEvent(MouseEvent) と timer 、確かに。Chromium 56.0.2924.76。

dblclick で動くわけでもないので、 ブラウザ側の tick/timer/job queu(e)ing あたりか .click() の仕様とか内部で気を効かせてそう。

http://ptech.g.hatena.ne.jp/noromanba/20170302#c1488736902

連打は?

noromanba

body = window.document.body;
body.onclick = () => console.log('ouch!');
for (i = 0; i < 10; i+=1) {
  body.click();
}
// -> (10) ouch!

えっ、ネストか

http://ptech.g.hatena.ne.jp/noromanba/20170302#c1488738344

書いたみたいに .click() 内部の debounce (throttle) とか、tick/timer/job queu(e)ing かと思ったんだけど、なんなんすかね。

どっかに書いてありそう。


環境

Chromium56.0.2924.76 (Developer Build) Built on Ubuntu , running on Ubuntu 16.04 (32-bit)
Revision314da7cc1e56fc9fa9271bac2b029922feb4b6f2
OSLinux
JavaScriptV8 5.6.326.42
User AgentMozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36
$ apt policy chromium-browser
chromium-browser:
  Installed: 56.0.2924.76-0ubuntu1.16.04.1271
  Candidate: 56.0.2924.76-0ubuntu1.16.04.1271
  Version table:
 *** 56.0.2924.76-0ubuntu1.16.04.1271 500
        500 http://ppa.launchpad.net/canonical-chromium-builds/stage/ubuntu xenial/main i386 Packages
        100 /var/lib/dpkg/status
トラックバック - http://ptech.g.hatena.ne.jp/noromanba/20170305

2017-03-02

同イベントのハンドラがネスト構造なコード

06:46

最初に断っておくと、ネストを積極的に使う理由はないので極力避けましょう。しかし読む場合はあるし、書かなければいけないこともあるでしょう。つらい。

外側のハンドラ末尾で再度イベントが発生、内側のハンドラが呼ばれる、という構造でハマったのを書いた。解決したので解説みたいなものを書いていく。

外側ハンドラ末尾で再発生してるイベントを見落とした結果、理解出来ない挙動に *見えていた* という話で、再現失敗してたところ、a-kuma3 さんがコメントしてくれて気付いた。

理解と再現出来た。ただ、自分の検証コードで再現再失敗してまたわからない挙動が出てきてしまった。ウケる。

言葉ではわかりづらいので実際の例見てもらった方が早い。a-kuma3 さんがコメント後、さらにハイクしてくれたのがミニマムでわかりやすいので引用。ハイクの仕様で全角スペースなところを半角変換したのでコピペ再現出来る。

onload = なのは元コードがそうだったから。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.onload = () => {
  console.log('outer');
  xhr.onload = () => {
    console.log('inner');
  };
  xhr.open('GET', location.href);   // もう一回 open
  xhr.send();
};
xhr.send();
// -> outer
// -> inner
no title

順序は、

  1. 外側のハンドラが登録されるが何もしない
  2. 最後の xhr.send();load イベント発生
  3. 外側のハンドラが動く
    • xhr.onload を内側のハンドラが上書きするが何もしない
  4. 外側のハンドラ末尾の xhr.send(); で再度 load イベント発生
  5. 上書きした内側のハンドラが動く

という流れ。イベントドリブン初心者は理解キツそう。

このように外側と同じく内側も同じ順に書くと、自然。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.onload = () => {
  console.log('outer');
  xhr.open('GET', location.href);
  xhr.onload = () => {
    console.log('inner');
  };
  xhr.send();
};
xhr.send();

open() -> onload -> send()

open() -> onload -> send()

addEventListener() ならこんな感じ。ちょっと長くなる。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);

outer = () => {
  console.log('outer');
  xhr.removeEventListener('load', outer);
  xhr.open('GET', location.href);
  xhr.addEventListener('load', () => {
    console.log('inner');
  });
  xhr.send();
};

xhr.addEventListener('load', outer);
xhr.send();
// -> outer
// -> inner

removeEventListener() 無いとハンドラが無限ループするので注意。

ネストしない

大抵の場合、こういう感じっぽくフラットに書ければ混乱しづらい。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.addEventListener('load', () => {
  console.log('I was outer');
  // ...
});
xhr.addEventListener('load', () => {
  console.log('I was inner');
  // ...
});
xhr.send();
// -> I was outer
// -> I was inner

しかしネストしてたということは、逐一 fetch しなければいけない状況があるはずで、これでは動かないどうしよう…。

といった背景も一因になって DeferredPromise 等色々生まれてるので適宜やっていきましょう。

再現再失敗

ハイクで返事貰う前、「XHR より click イベントがお手軽そう」と思ってこんなコードを書いたら違うカルマを背負った。

body = window.document.body;
body.onclick = () => {
  console.log('outer');
  body.onclick = () => {
    console.log('inner');
  };
  body.click();
};
body.click();
// -> outer

アイエエエ!?」.click() が マズイのか、キャプチャリング・バブリングとかフェーズの問題なのか、単純にコードが間違ってるのか。

すぐ時間が無くなってとりあえずあきらめた次第。


続き書いた。

a-kuma3a-kuma32017/03/03 09:53.dispatchEvent(MouseEvent) だと、内側も発火した >Firefox

const do_click = (e) => {
 const clickEvent = new MouseEvent("click", {
  view: window,
 });
 e.dispatchEvent(clickEvent);
};

body = window.document.body;
body.onclick = () => {
 console.log('outer');
 body.onclick = () => {
  console.log('inner');
 };
 do_click(body);

};
do_click(body);


.click() を setTimeout() でずらしても、発火した。

setTimeout(() => body.click(), 0)

unaristunarist2017/03/03 21:57ちなみに最初はインスタンス使いまわせないと思っていて、コピペしてインスタンスだけ変えた、つもりが変わってなくて使いまわせることに気づいた感じですね。
# でも気持ち悪いなーと思ってたら見事に勘違いされたので、ネタ以外では使わないようにしよう…

noromanbanoromanba2017/03/06 03:01> a-kuma3
検証 thx です。`.dispatchEvent(MouseEvent)` と timer 、確かに。Chromium 56.0.2924.76。

body = window.document.body;
body.onclick = () => {
console.log('outer');
body.onclick = () => {
console.log('inner');
};
settimeout(() => body.click(), 0);
};
body.click();

`dblclick` で動くわけでもないので、 ブラウザ側の tick/timer/job queu(e)ing あたりか .click() の仕様とか内部で気を効かせてそう。

noromanbanoromanba2017/03/06 03:13> unarist
> 使いまわせることに気づいた感じ
なんと…。小さいとライブラリの導入もアレなんで、もしやるなら標準の Promise.all Promise#then するのがいいのかなー。「フラット化どうよ」みたいな声もありますが、気にせずやっていきましょう

noromanbanoromanba2017/03/06 03:25body = window.document.body;
body.onclick = () => console.log('ouch!');
for (i = 0; i < 10; i+=1) {
body.click();
}
// -> (10) ouch!

えっ、ネストか

2017-03-01

ネストした同イベントハンドラ代入式

05:15

単純に外側のハンドラ内で再度イベントが発生、内側のハンドラが呼ばれる、という構造だった。

記事あげてから、id:a-kuma3 さんがコメントしてくれて気付いた。

2017/03/02 08:51 by a-kuma3

ありがたい。

ハマりどころ

外側のハンドラの最後で readAsText() 呼んでるところで load 発生するの見落としてた。

FileReaderreadAs*() 完了時全般で load 発生するの、自分でMDNのリンク貼ったのに。

  • 眠気を感じる時や疲労時はコードの運転を控えましょう
  • 余裕を持ってコードの「かもしれない運転」を行いましょう

というのがぼくからの言葉です。長いので謎解きは新しい記事にした。

ではハマってる様子をどうぞ。


混乱避け・拡張性とか考えて普段 receiver.addEventListener() しか使わないのだけど、receiver.onload = ... が理解超えた挙動する。詳しい人教えて欲しい。JavaScriptの話です。

via

readerFileReader

現在のドキュメントを文字コード自動判定で読み直す - Hatena::Let

これ outer -> inner 走るんだけどマジか…

reader.onload = function() {
  // outer ...
  reader.onload = function() {
    // inner ...
  };
};
no title

上みたいな感じで onload = function(){} がネストしてて両方順番に走る。

id:unarist さんが書いたこのリビジョン。

console.log 入れて確かめた。

  reader.onload = function() {
    console.log('outer');
    //  ...
    reader.onload = function() {
      console.log('inner');
      //  ...
    };
  };
// -> outer
// -> inner

アイエエエ!?」「ネスト!?ネストナンデ!?」

うーん、+= みたいになるの? C#delegate w/ 演算子オーバーライドみたいな。

再現失敗

手っ取り早くXHRでテスト書いたところ、理解は出来るけど再現出来なかった。

xhr = new XMHttpRequest();
xhr.open('GET', location.href);
xhr.onload = () => {
  console.log('outer');
  xhr.onload = () => { console.log('inner'); };
};
xhr.send();
// -> outer

これはこれで一瞬ビックリだけど、 onload 入った時に発火終わってるって考えると普通に見える。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.addEventListener('load', () => {
  console.log('outer');
  xhr.addEventListener('load', () => { console.log('inner'); });
});
xhr.send();
// -> outer

addEventListener() も同じ。

FileReader が特別なようには見えないんだけどなー。

「オメーのコードが間違ってんだよハゲ!」とか、「テメーの目はフシアナか?どう読んでんだよアアン!?」とか、「コンコンコン、もしもーし?脳みそ入ってますかー?」みたいなのも助かります。


APPENDIX

環境
$ apt-cache policy chromium-browser
chromium-browser:                             
  Installed: 56.0.2924.76-0ubuntu0.16.04.1268 
  Candidate: 56.0.2924.76-0ubuntu0.16.04.1268 
Chromium56.0.2924.76 (Developer Build) Built on Ubuntu , running on Ubuntu 16.04 (32-bit)
Revision314da7cc1e56fc9fa9271bac2b029922feb4b6f2
OSLinux
JavaScriptV8 5.6.326.42
Flash24.0.0.221 /usr/lib/adobe-flashplugin/libpepflashplayer.so
User AgentMozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36
Command Line/usr/lib/chromium-browser/chromium-browser --ppapi-flash-path=/usr/lib/adobe-flashplugin/libpepflashplayer.so --ppapi-flash-version=24.0.0.221 --enable-pinch --flag-switches-begin --overscroll-history-navigation=0 --disable-smooth-scrolling --disable-features=CredentialManagementAPI,MaterialDesignHistory --flag-switches-end
Executable Path/usr/lib/chromium-browser/chromium-browser
Profile Path/home/noro/.config/chromium/Default

> chrome://version/

フラットな時

普通のやつの挙動です。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.onload = () => console.log('#1');
xhr.onload = () => console.log('#2');
xhr.send();
// -> #2

最後に代入したやつが出る。そりゃそうですね。

xhr = new XMLHttpRequest();
xhr.open('GET', location.href);
xhr.addEventListener('load', () => console.log('#1'));
xhr.addEventListener('load', () => console.log('#2'));
xhr.send();
// -> #1
// -> #2

くっつけただけ全部出る。そりゃそうですね。

a-kuma3a-kuma32017/03/02 08:51ハンドラの中で、もう一度 発火しているから。

const reader = new FileReader();
reader.onload = function() { <-- (*1)
...
reader.onload = function() { <-- (*2)
...
};
reader.readAsText(xhr.response, enc); (*2)
};
reader.readAsArrayBuffer(xhr.response); (*1)

noromanbanoromanba2017/03/03 03:45なるほど!

トラックバック - http://ptech.g.hatena.ne.jp/noromanba/20170301

2017-02-10

Re: id:pacochi

06:54

最近 Hatena::Let に人が戻ってきたり、新規参加の人も増えたりしてうれしい。pacochi さんは昔から Let で見かけてて面白いの書くなーと思ってた人で、最近ブログに気付いて面白そうな記事が沢山あった。

ぼくは読みたいブログは古い順に消化する習性があるのだけど、大体今日の他の記事内容見てもらえばわかる通りの体たらくなので、まだ全然ちゃんと読めてない。仕方ないのでナナメ読んで気になった直近のやつ、急ぎ足で殴り返信としたい。

はてなスターは宇宙である

特性js 読める人だけわかって欲しいのでコードだけ。こういうのがあってそれでやってます。SHA-1廃止で止まらなかったのは意外。

どこでも存在するし、時間経つとエントロピー増大して消せなくなる。宇宙。

実際手元のコード違うけど、オンライン上に置いてない。

ここではない場所で js わかんない人にはてなスター系でうるさく言われた経験あって、多分面倒になったのが理由です。Beautify して下さい。

javascript:(()=>{const%20canonical=()=>{return(document.querySelector('head%20meta[property=%22og:url%22][content]')||{}).content||(document.querySelector('head%20link[rel=%22canonical%22][href]')||{}).href||location.href;};const%20canon=canonical();window.open('http://s.hatena.ne.jp/mobile/entry?uri='+encodeURIComponent(canon));})();

js、同じく MIT License です。

このブログでも過去に仕様を調べたので検索すると暇つぶしになるかもしれません。仕様も良くわからない感じになってたりするけど宇宙なので仕方ない。

検索出ないの

なんかスターの奴も出なかったんで嫌われてるんですかね。

Captcha・No CAPTCHA Recaptcha 出まくるしbot扱いされてそうです。

マトモな検索エンジンご利用下さい。

こっちなら出ます。


ぼくはエゴサーチしないので、ブログ読んでて自分のid出てきた時死ぬほどびっくりしました。光栄です。

「コミュニケーションなんかしたくない」

06:54

大体字面通りで、良いコミュニケーションと考えてるのが多分世間乖離してる。

  • コードだけでやり取り済めば最高
  • 記事だけでやり取りするのも良い
  • リアクションコストは低いのがいい
  • 文字コメントは最高にダサい方法
    • 返信コストがダルい

「push通知」という言葉が出来る前から通知は最悪の方法だと思っていて、相手が見たい時に初めて気づく、みたいな能動スタイルが良いと感じてる。

上に書いた理由が SNS をやらない一因になってるし、メールがここまで残ったのもWebメール主体になって、割り込み阻害する事が少なくなったからだと勝手に思ってる。

idコール/コメント殴り

とは言うものの、困ったことに世間トラックバック(TB)のないはてなブログを使う人か脱出した人が多勢になってしまって、TB で記事返信する事が難しいので仕方なくidコールするか、コメントしなければ気付いてもらえない。

「殴り」というのは別にマサカリを振り回したいわけでなく、人に割り込むのが嫌と言ってるやつがそういう事をせざるを得ないので自嘲言葉として使ってる。

id:jkondo は当初「トラックバックを必要とする人はいませんでした」的な発言をしていたけど、結局言及通知が付いた。そりゃそうだ。そんな世界はてなじゃないし。困ったことにはてなブログ間でしか通用しないのと、ぼくに使う予定が無いので殴るしか無い。

重い上にはてなダイアリーの要件も満たしてないもの再発明してるのは完全に無駄と思っている。そろそろ拡張はてな記法実装されましたか。まだですか。そうですね。


正確な意図覚えてないけど、元々有名なロックスターエンジニアが言ってた気がするので「」付きにした。

2016 - Early 2017 近況

06:54

色々あって、時間が取れない・喫緊のタスクが溜まっていて、モバイルからハイクにゴミをまき散らす位しか出来ないでいる。知性が低下してるのを感じる。コードじっくり読む時間も余裕もない。

元々ゴミみたいなコメントか闇を投げるかやむを得ずidコールする用なのでいきなりすさんだ、とかではない。つぶやきは元来下らないものなので正しい使い方ではあるけど、気分を害す人はいそう。

今日の記事も雑な感じで書くしか無いので、どうしてもと言う人は上述のゴミ溜めTL覗くと何考えてるか少し把握出来るかもしれない。

文書くべきか

元々ブログは自分のワーキングセットを出して後で見返す用に使うことが多い。今は記事出す時間が無いので手元にURL溜めてるのだけど、

$ ls *.session | wc -l
44
$ cat *.session | wc -l
1427

溜まりすぎ。そもそもここが、しっかり書いた記事だけ置く場所、みたいになってきてしまっていて、そういう期待があるのが若干つらい。昔みたいに短いポエム書いた方がゴミTL出すよりマシかなと思ってる。

トラックバック - http://ptech.g.hatena.ne.jp/noromanba/20170210