@miyamonz
s/待遇/対偶/g
thanks!miyamonz.icon
s/mouseup字の処理/mouseup時の処理
修正miyamonz.icon
ご参考までにどうぞ
code:sample.js
import {listen} from './listen.js';
for await (const event of listen(window, 'mousedown')) {
const downPos = {x: event.clinetX, y: event.clientY }
for await (const mouseEvent of listen(window, 'mousemove')) {
/* drag中の処理 downPosも参照できる */
}
あ、これだとmousemoveで無限ループが発生してしまうのか。まずいな
mouseupが発火したことを示すflagを導入し、flagが経ったらループを抜ける処理を追加しないと行けない
そうそうmiyamonz.icon
ここらへんのこと一回考えた気がするのだが、忘れてしまったな
mosemoveのfor awaitのループ内のどこかの一行でupがresolveされたかチェックするのはだめ
それ以外のところでawaitして、upのチェックができないタイミングがあるから
for awaitを外側からrejectできないとだめになり、無理になる
code:sample.js
const upEvent = await mouseUpPromise()
// mouseup時の処理
}
code:listen.js
function getPromise() {
let _resolve;
const update = () => new Promise((res) => _resolve = res);
const resolve = (value) => _resolve(value);
}
code:listen.js
export async function* listen(element, type) {
let done;
const callback = e => resolve(e);
element.addEventListener(type, callback);
try {
while (true) {
const event = await done;
done = update();
yield event;
}
} finally {
// 後始末
element.removeEventListener(type, callback);
}
}
miyamonz.icon
memo
後でもうちょっと見ます
update->getPromise
最初のwhile ループでdoneに代入がされてないかeventがundefinedにならないか?
本当だ。確かにundefinedですねtakker.icon
じゃあなんでこれで動いたんだろう……?
単に最初にundefinedが返ってくるだけで、エラーにはならないからか
でもこの挙動は確かにおかしいですね
code:js
while(true) {
yeild await update()
}
whileの部分、これでよいのでは?miyamonz.icon
動かしてないので想像だけど
これでよかったですtakker.icon
mousemoveをmouseupされるまでemitするとかの処理を良い抽象作ろうとするとRxJS使えよって話になる この素振りをした後にrxjsについて詳しくなったので、この時点でrxjs使うのは考えてなかったmiyamonz.icon
めちゃくちゃ面白いyuki_minoh.icon
僕もアイデアがあるので書き直してみます
code:baseline.js
// ベースライン実装
function mouseDown(event) {
console.group("mouseEvent");
console.log({ mouseDown: event, time: event.timeStamp });
window.removeEventListener("mousemove", mouseMove);
window.addEventListener("mousemove", mouseMove);
window.removeEventListener("mouseup", mouseUp);
window.addEventListener("mouseup", mouseUp);
const downPos = { x: event.clinetX, y: event.clientY };
function mouseMove(event) {
console.log({ mouseMove: event, time: event.timeStamp });
// downPos
}
function mouseUp(event) {
console.log({ mouseUp: event, time: event.timeStamp });
window.removeEventListener("mouseup", mouseUp);
window.removeEventListener("mousemove", mouseMove);
console.groupEnd("mouseEvent");
}
}
window.addEventListener("mousedown", mouseDown);
console.groupを使って、mouseDown ~ mouseUpをグループ化して表示する
多重呼び出しがあればみてすぐにわかるようになる
この実装が一番いいような気もしないでもない
thenチェーンで柔軟性を高めた実装
code:promise.js
const controller = new AbortController();
const signal = controller.signal;
function onAbort() {
console.log("aborted");
}
// controller.abort();
let promise = Promise.resolve();
const update = () => {
promise = promise.then(mouseDownChain).then(onMouseDown, onAbort);
// .catch(onHandleError);
};
update();
function mouseDownChain() {
return new Promise((resolve, reject) => {
window.addEventListener("mousedown", resolve);
signal.addEventListener("abort", reject);
});
}
function mouseMoveChain() {
return new Promise((resolve, reject) => {
window.addEventListener("mousemove", resolve);
window.addEventListener("mouseup", reject);
});
}
function onMouseDown(event) {
console.group("mouseEvent");
console.log({ mouseDown: event, time: event.timeStamp });
update();
let movingPromise = Promise.resolve();
const innerUpdate = () => {
movingPromise = movingPromise
.then(mouseMoveChain)
.then(onMouseMove, onMouseUp);
// .catch(onHandleError);
};
innerUpdate();
const downPos = { x: event.clinetX, y: event.clientY };
/* mousedown */
function onMouseMove(event) {
console.log({ mouseMove: event, time: event.timeStamp });
innerUpdate();
/* mousemove */
}
function onMouseUp(event) {
console.log({ mouseUp: event, time: event.timeStamp });
/* mouseup */
console.groupEnd("mouseEvent");
}
}
こうしてみるとお二人のよりかなり長い?
割と「ちゃんと」書いてしまった
コメントとかconsole APIを削ればそうでもないかもしれない
利点
abort対応済み
Promiseの外側でrejectをできるようにすれば同様のことができそうだが
普通にできます!yuki_minoh.icon
お好きなテイストでどうぞ
僕はresolve/reject持ち出しパターンがあまり好きでない()
yuki_minoh.icon的にはBad Practiceのような気がしている。。。
エラー処理も簡単
拡張性が高い
thenチェーンの組み替えによる処理の変更、catch functionの追加によるエラー処理、resolve, reject条件の変更など
chain functionを切り出せているのが特に強みかもしれない
resolve, reject条件の変更ができると、待機条件やthrow errorとかに柔軟性が出る(多分)
せっかく書いてもらったのにコードが何やっているか分からない…miyamonz.icon
ここらへん、removeしたあとにすぐaddしてるのはなぜ?
ナイーブに実装したらイベントハンドラが重複して困ったので、一つのイベントに対して一つのハンドラだけが応答するように調整したらこうなりましたyuki_minoh.icon
唯一性を担保するのが面倒だからremoveとaddを同時にやってます。。。
ここがなんども呼び出される前提で、初回のremoveは無視させるということか、理解しましたmiyamonz.icon
miyamonz.iconさんが考えたScrapJupyterという名前をそのまま使ってGitHubに載せてしまいましたtakker.icon
事前に了承をとらずに使ってしまい申し訳ありません。問題があれば名前を変えようと思います
miyamonz.iconさんのUserScriptを参考に作ったという旨はcreditに書きましたが、もし何か不足があればご指摘をお願いします。 おけまるmiyamonz.icon
たぶんs/\sim/\infinity
$ \lim_{n\rightarrow\infty} \bold{x}_n = \bold{a} ならば $ \lim_{n\rightarrow\infty} f(\bold{x}_n) = f(\bold{a})
={resolve}かな?
thanks!miyamonz.icon
firefoxでも無理だったぞ
うそんtakker.icon
takker.iconはFirefoxで使っていますが、一度もエラーは出ていません
昨日も今日も使えてます
まさかFirefoxに個体差があるとか?
なんか使ってる拡張機能とか関係あるのかも?miyamonz.icon
firefox普段使ってないんで追い調査めんどいけど、気が向いたらやってみます
miyamonz.iconさん現在3DプリントやFusion360のお勉強されているようなので関係ありそうなこと書いておきます、おせっかいでしたらすみません~imo.icon 直接線を引いたり形状を組み合わせたりするのではなく、モディファイアを足したりビジュアルプログラミングみたくノードを繋げたりして立体を作る手法なのですが、miyamonz.iconさんの文脈だとすんなり受け入れられるかも?
お、ありがたいmiyamonz.icon
実はそういう他のソフトもちょっとは調べてるのですが、これだ!というのを見つけられて無くて
ユーザが多いからFuson360には慣れておくと良いかも、とは思うものの、本当はコードとかパラメトリックにやりたいですね
OpenSCADとか
お、なるほどです~imo.icon
s/動的なimport/import
これどういう意味です?miyamonz.icon
どういう意味なんだろう……?(おい)takker.icon
おそらく当時の記述にdynamic importがどうのこうのみたいな記述があって、それはstatic importでも普通にできるみたいなことを言いたかったのかもしれません
履歴見るとmiyamonz.iconが自分で気づいて消したのかも?miyamonz.icon
あざすmiyamonz.icon
wandboxに投げるの、なるほど