+ JavaScript の質問用スレッド vol.126 +
■ このスレッドは過去ログ倉庫に格納されています
JavaScript を自ら学ぶ人のための質問スレッドです。
■質問を書く上で
(1) 煽り、コード制作依頼等、人を不快にさせる投稿はご遠慮下さい。公序良俗を守った応対を心がけてください。
(2) 他の人に迷惑をかけるスクリプトの質問はご遠慮ください。
(ブラクラ、[戻る], [閉じる], [クリック] の妨害、画面占有など)
(3) 質問者及び議論を行う人はメール欄を空欄にし、名前にレス番を入れることを強く推奨します。回答者はなりすましを判断できませんので、なりすましが現れても自己責任となります。
(4) 常に自発的に調べる心構えを持ってください。
具体的には「自分で調べてから質問する」「回答をもらってわからない単語があればGoogle検索してみる」など。
わからない内容を代わりに調べてくれる回答者をお望みの方は余所で質問してください。
(5) 出来るだけ一般的な用語を使用してください。脳内オレオレ用語は混乱の元です。
(6) 出来るだけサンプルコードを掲示してください。言葉による説明は行き違いが生まれる場合があります。
※必ず「問題の事象が再現されること」を確認してください。
必要な部分だけ切り出したつもりで現象が再現できていなかったケアレスミスがしばしば見られます。
(7) サンプルコードに HTML が含まれる場合は http://validator.w3.org/ で [Check] してみてください。
(8) 質問を具体的かつ詳細に書くと回答を得られやすいです。>>2の質問テンプレートを活用してみてください。
(9) 時にはあなたが望む「答え」だけでなく、「意見」などが寄せられる場合もあります。
前スレ
+ JavaScript の質問用スレッド vol.125 +
https://mevius.5ch.net/test/read.cgi/tech/1518940081/
(ライブラリ禁止条項は、多数の意見によって廃止されました。ライブラリの質問もOKです) + JavaScript の質問用スレッド vol.126 + まずスレチすいませんでした
こういうのをどこで質問していいかわからず、もし使ったことのある人がいるならこのスレかなと思いここにしてしまいました
どうにか解決したので報告だけさせてください
>>680
すごくヒントになりました
結局dllは不足なかったことがわかり不思議でよく考えてみたところ
wscriptのほうもSystem32のものではなく、SysWOW64の32ビットのものを指定して実行したところ問題なく使うことができました
わかってみたら単純なことでしたが思いこんでました
ありがとういございました JavaScriptの非同期の書き方がまだおぼつかないのですが
var defarr = [];
for(x of list) {
var d = new $.Deferred();
$ajax(...)
.done(() => { d.resolve() });
defarr.push(d.promise());
});
return $.when.apply($,defarr);
みたいな感じでAPIからデータをとってきて画面に非同期で順番に表示する
みたいな処理があるときに
途中で中断したいときどこにどういうコードをはさめばいいんでしょうか 中断の伝播とか真剣にやってるとやっぱり複雑になってきたときにバグるよ
手抜きして要素を非表示にしたりメインツリーから消したりして
表示までの処理は動いてるけど機能しない状態にするのが一番お手軽で安全 requreを使っているfile.jsライブラリファイルをインポートできなくて困っています。
file.js内には「func」という関数が定義されていて
これをインポート先で呼び出したいとします。
ただし「file.js」内部にはrequireが使われていて
これに失敗します。
.htmlファイルから
scriptタグのsrc属性で読み出す。
普通なら 「file.func()」で関数を呼び出せる
のですが、
requireが失敗するためにfile.jsをbrowserify
で変換しました。
変換後はrequireが使えるようになりますが
変換の影響でfile.js内部のコードが変なコードで
囲まれて内部で定義されている関数「func」
がインポート先から見つけられなくなってしまいます。
requireを内部で使っているファイルを
.htmlのscript src属性でファイルパスで読み込んで
内部の関数を呼び出すにはどうしたらいいでしょうか? ライブラリLAB.jsの質問
script src="LAB.js" で読み込んだあとで
$LAB
.script("jquery.js").wait()
.script("jquery.ui.js")
.script("jquery.lightbox.js")
.wait(function() {
$(document).ready(function() {
$('#gallary').lightbox();
});
});
とすると実行されるのですが、
htmlにscript src="LAB.js" を書かずに
下記にあるように、LABjsを動的に読み込むと
$LABが未定義ってなるのですが、
このように〜.jsを動的に読み込んだ後ってどうすればコードが
動くのでしょうか?
load LABjs itself dynamically!
ttps://gist.github.com/getify/603980 JavaScript の質問は、web制作管理板の方へ書き込んでください!
こちらのスレは、答える人が少ない
>>683
頼んでいた非同期処理を、中断・取り消すのか。
そういうのは、できるかな?
「javascript 非同期処理 中断」で検索!
>>685
「javascript require commonjs」で検索!
>>686
「javascript 動的 読み込み」で検索! >>687
document.onreadystatechange = function() {
if (document.readyState == "complete") {
$LAB (以下略)
}
}
ありがとうございました。これで動きました。 これほど書き方が統一されていない言語あるかね?
function書くだけなのにいくつもパターンありすぎ pythonは関数を書くときにdefとlambdaがある つまり未だにアロー記法を採用してくれないPHP最強ってことだな
何回function書かせるねん 打つのが面倒でないならjavascriptでも全部functionで通してもええんやで。
所詮(function () {}).bind(this)の糖衣構文に過ぎない。 入力補完でfunctionを打つのは楽だから、基本はfunction使う
アローより可読性高いから
ワンラインで済むときと、thisを受け継ぎたい時だけアロー使う mapとかfilterの引数もfunction渡すの?
複数行あるならともかく、一行で済むものにわざわざfunctionとreturn書くのは、可読性の観点だと逆効果のような >>695
> ワンラインで済むときと、thisを受け継ぎたい時だけアロー使う
> ワンラインで済むときと、 > 所詮(function () {}).bind(this)の糖衣構文に過ぎない。
糖衣構文って素晴らしいよね 念のため、素晴らしくないとは言ってないからな。
functionでも書けるから、そうしたいならどうぞご勝手に、という話。 アロー使ったら複数行でもreturnなしにしてほしい
最後の行の値を返せばいいだけと思うけど、難しいのかな むしろアロー関数は1行でしか使えないようにしてほしいくらいだ yield 文って、generator function から呼び出された普通の関数の
中で使うとどうなる?
エラーになるか、それとも、あたかも、親の generator function
の中から yield 文が実行されたかのように動作するかどちら?
書き方は間違ってるかもしれないけど、こんな感じの事やったらどうなる?
function *func1() {
yield 1;
func2();
yield 3;
}
function func2() {
yield 2;
}
console.log( func1().next() );
console.log( func1().next() );
console.log( func1().next() ); エラーになるかどうか知りたいの?
コンソールに張り付けろよ var aaa = func1;
console.log( aaa.next() );
・・・
みたいに修正してから、やってみたら func2() 内の yield でエラーが出た。 function* func1() {
yield 1;
yield* func2();
yield 3;
}
function* func2() {
yield 2;
}
俺のESP能力が高ければこれが助けになるだろう。 >>706
それだと、func2() も generator function になるよね。
自分が思っていたのは、もし、普通の関数でも
yield が使えれば、JS でも、SetEvent() と WaitForSingleObject()
みたいな同期オブジェクトを作れるんじゃないかということだった。
そうすれば、wasm を使って、Windows プログラムも移植できるの
ではないかと思った。 >>707
それは何の為に?
WebAssembly(wasm)なら移植の必要すらなく動かせる(はず)だろ。
それ以前にGraalVMなんてのも出てきたみたいだが。
> JavaScriptだけでなくあらゆる言語をブラウザで扱えるように、GraalVMをChromiumにリンクすることを考えた学生が1人います。
> https://www.infoq.com/jp/news/2018/05/oracle-graalvm-v1
>>705
インタプリタがある言語(≒スクリプト言語)なら通常のデバッグ方法だ。 >>707
普通の関数でyieldが使えてもそれはジェネレータ関数ができること以上のことができるようにならないだろう
結局処理は同期的で待ち合わせには使えないのだから
async関数でというのなら分かるがそれはもうasync generatorがある やっぱ、数学ができない人にはわからないんだと思う。
ちなみにおいらは数学は主席。
今のwasmは、sleepはできるが、SetEventやMutex などを
待つことができないので、
>WebAssembly(wasm)なら移植の必要すらなく動かせる(はず)だろ。
これは違う。
すまんが、何度説明しても分からん人には分からん。
日本語の問題ではない。句読点の問題でもない。数学の問題なんだ。 WASMはもう実験的にSABとAtomicsサポートしてるでしょ
何を知ったげに言ってるんだか >>712
wasm は、emscripten_sleep(millisecond) をサポートしてるので、もともと問題の根は浅い。
でもあなたの言ってることはSetEvent()やMutex()などの同期オブジェクトとは直接関係
ない。それに proposal 段階で、実装報告は見当たらないんじゃないの。 【数学首席のオイラが書く(言葉の美しさは知らん)】
atomic fence は、二つのスレッドが同時に読み書きすることを防ぐ目的で使うもの。
たとえば、グローバル変数 a に「1足す」場合、CPUは、それをいったん(内部)
レジスタなどに読み取ってから、1足し、最後に同じグローバル変数 a に書き戻す。
この際、二つのスレッドがほぼ同時に「読んで」しまった場合、合計で「2」を足して欲しいのに、「1」しか足されなくなってしまう。それを防ぐために、ある同時に「読む」ことすら防ぐフェンスのようなものを用意するためのもの。だから、専用APIとして、
InterlockedIncrement() があったり、CPU自体にもマシン語レベルでLOCK修飾なるもの
があったりする。
一方、SetEvent() などのイベント発生を「待つ」ことは、この仕組みだけでは不十分で、
次のような単純なやり方では CPU がフルパワー状態になり、電力の無駄使いになる。
ちなみに、このように (HLT 命令を使っていない) BUSY LOOP では、CPU の 電力消費
が何十倍にもなることがある(だから、sleep()命令は特殊な実装を行ってる)。:
ATOMIC_FENC g_fence;
BOOL g_bEvnet = 0;
void mySetEvent() // スレッドBが使うとする。
{
g_bEvent = 1;
}
void myWaitForEvent() // スレッドAが使うとする。
{
// 以下ループで、CPUがフルパワー状態になり電気の無駄使いになる:
for ( ;; ) {
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
if ( !g_bEvent ) {
g_bEvent = 0;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
break;
}
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
}
} >>715
[続き]
そこで今度は、myWaitForEvent()のループを次のように書き換えたとする:
for ( ;; ) {
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
if ( !g_bEvent ) {
g_bEvent = 0;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
sleep(100); // 100(ms) 待つ。
break;
}
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
}
この場合は、電力消費はかなり抑制されるが、スレッドBで mySetEvent()が呼ばれて
から、スレッドAのmyWaitForEvent()がそれを知って、ループから脱出するまでに、
最悪100(ms)の遅延が発生してしまう。だから、OSは、WaitForSingleObject() API
などの専用の同期メカニズムを用意しなくてはならない。Emscriptenにはまだそれ
が整備されていない。 >>715
【修正】
void mySetEvent() // スレッドBが使うとする。
{
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
g_bEvent = 1;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
} >>716
【修正】
誤:if ( !g_bEvent ) {
正:if ( g_bEvent ) { >>715
【sleep()を使う場合の最もましなコード】
(それでもどうしても遅延が発生する。)
void mySetEvent() // スレッドBが使うとする。
{
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
g_bEvent = 1;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
}
void myWaitForEvent() // スレッドAが使うとする。
{
// 以下ループで、CPUがフルパワー状態になり電気の無駄使いになる:
for ( ;; ) {
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
if ( g_bEvent ) {
g_bEvent = 0;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
sleep(100); // 100(ms) 待つ。
break;
}
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
}
} >>719
【修正】
誤:// 以下ループで、CPUがフルパワー状態になり電気の無駄使いになる:
正:// 以下ループで、最悪100(ms)の遅延が発生する。 >>719
【再修正】
void myWaitForEvent() // スレッドAが使うとする。
{
// 以下ループで、最悪100(ms)の遅延が発生する。
for ( ;; ) {
BeginAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの開始。
if ( g_bEvent ) {
g_bEvent = 0;
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
break;
}
EndAtomicFence(&g_fence); // あなたが言ったAtomic Fenceの終了。
sleep(100); // 100(ms) 待つ。
}
} いや、もうAtomicsAPIがChromeでオリジントライアルで使えるでしょ
もう解決してる問題に対して何をイキっちゃってんの
いくら数学の理論構成や計算ができようと意味はないよ
そんなのは機械でできることだから
正しい問題と前提を認識できて初めて数学という道具は有益に使えるんだから
君がやってるのはただ思考力の無駄遣い
まあ君の頭だからどう無駄に使おうと勝手だけど、スレ汚しは勘弁してね >>722
なるほど、Atomics の wait() と notify() の事か:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait
分かった、すまんかった。
しかし、海外のサイトを検索しても、この関数のことは一切発見することが出来なかったんだよ。
await や async や、その他の便利ラッパクラスみたいなものより、こっちの関数の方が重要だ。
初見だが、多分、notify() と wait() が、Win32API の SetEvent() と WaitForSingleObject() に大体
対応していて、それがあればスレッドの同期に関してはほとんどの用途では足りると思う。
効率の良い(電気もCPUパワーも無駄にしない) sleep() もこれらを使えば実装できてしまうだろう。 またWindowsのAPIに固執してるの?
いい加減に理解しなよ。Windowsとwebは無関係だって。 マルチプラットフォーム環境として、wasm や JVM や CrossBrdige(FlashCC) など
を調査してるから、Windowsアプリが移植できるかどうかに興味があるんだ。 Windowsアプリが移植できるかと、同じAPIを持ってる事は無関係だし、
事実同じAPIも持ってないよね。
なのに見立てる理由がわかんない。 基本的にLLVMに変換可能なプログラムなら移植できるけど
OS特有のAPIやライブラリ使ってちゃそりゃそのまま移植できるはずがない やっちゃおう、にどれだけ価値があるかわからんけどね。
そこまで言うなら、前回のIMEだって、やっぱりIMEを移植すべき問題じゃん。
同じAPI使うってのは、wasmでのWin32API互換ライブラリを作るって夢を語ってるって事なのかな?
簡単な道ではないと思うけど。
WINE何年かかってんよって話。 WasmでというよりJSででしょ
現状Web API叩くのはJSからしかできないのだから foo =function(){}とか
bar = ()=>{} とか
エディタがDocコメ認識してくれないことが多くてなあ… jsdocって言語機能が名前から想像するよりはるかに異なるjava用のjavadocの単なるメクラポーティングだしなぁ…
js用にもっと相応しいドキュメント仕様が普及してもよかっただろうに世の中うまくいかんのう… iframe要素のsrcを変更したら画像のロードが終了してからloadが発火すると思うんだけど
この間(画像のロードしてる間)にiframeのHTMLにcss挿入するのってどうしたらいい? >>733
src を変える前に iframe の style 属性を指定しておくのでダメであれば、
別に、タイマーイベントみたいなので、少し遅れてから、イベントハンドラ
の中から iframe の style 属性を変えればいいだけではないの。 エクセルのマクロとかすら使ったことがないし
数学も超苦手なのですが
プログラムを始めてみたくてウズウズしてます。
仕事で使ってる動画ソフトが
javascriptでスクリプトを追加できるので
java scriptをはじめてのプログラムとして始めてみたいのですが
何から揃えればよいのでしょうか? >>738
確かに。
冗談のようだけど重要だな
Chromeなど開発モードがあるブラウザを使い、それの操作方法に多少は馴れておけって意味では 知識0なのに実用的なプログラムから始めるのは間違っている
HTMLを学んでてそこに動きを付けたいとかいう段階的な目的とステップがあるなら別だけど
マクロとしてのJSを学びたいのにWebに手を出すというのは無理筋
基本的に勉強用の非実用言語環境でできれば配列くらいの知識まで身につけといてから
Webとか手を出さないで直接マクロに行かないと絶対に挫折する マクロとしてのJSって何だよ・・・・
やりたいこととしてはブラウザよりNodeの方が向いているとは思うが いや、もうやりたいことは決まってるでしょ
いくら比較的余計な知識が要らないとは言え
NodeでのJS入門環境が充実してるわけでもないのに webpackで依存関係が数百とかなってわけがわからなくなる みなさんありがとうございます。
「なにかゲームしたい」くらいな感覚でプログラムをやってみたいと思ってました。
必要に迫られて始めたいわけではなくて
暇なときにテトリスする代わりに
クネクネ動くhello worldを作ったり
自分で使うようのアプリとか作れたら楽しそうだなと思った次第でした。
今は小さくて安い小型パソコンがたくさんあるのでそういうパソコンで
暇な時にシコシコプログラム作れたら
すごく楽しいんじゃないかと
ついでにJs覚えれば仕事の動画編集にも活かせそうだしなんか良いかなみたいな感覚でした。
htmlもかじってみようと思います。 Excelの表をGraphqlに変換することは出来ますか? >>748
続き
横幅やセルの色や結合までGraphqlでもっていけたらいいなぁと思うんですが・・ 質問です。下記のようなプログラムで、'テスト'をhoge内に記載する場合は
どのようにすればいいでしょうか?
const hoge = {
hoge1:'hogehoge1',
hoge2:'hogehoge2'
};
console.log(hoge.hoge1 + 'テスト')
イメージ的にはこんな感じにしたいです
const hoge = {
hoge1:'hogehoge1',
hoge2:'hogehoge2'
(hoge1+テスト)
};
console.log(hoge.hoge1)
結果:hogehoge1テスト const hoge = {
hoge1:'hogehoge1'
+'テスト',
hoge2:'hogehoge2'
}; >>748
gatsby-transformer-excelあったと思う >>746-747
メソッド一覧とかプロパティ一覧、関数一覧のページはMSDNのほうが見やすかったから
索引的なページは残しておいてほしかった
エディタのマクロ書くときなんかはMSDNのほうが都合よかったので残念 Electronでクロスプラットフォームのアプリ開発の出来ることを知ったプログラミング初心者ですが、一般的なElectronの開発はVue.jsやReact.jsを併用するのでしょうか? もうElectronは古い
今からはできる限りPWAでやる風潮 React学ぶのにオススメのチュートリアルや本ありますか? 本は薄い奴が今のところ比較的新しいけど、残念なことにそれでも情報が古いからGithubのreadmeとか見ないとダメ
その本に書かれているライブラリはもう開発停止していたりするから
ReactよりもReduxのほうが大変かもね >>758
Q. ○○を学ぶのにオススメのチュートリアルや本ありますか?
A. 公式
JavaScript界隈の場合はほぼ全部これ。
公式読んで無理なら諦めた方がいいと思う。当然だが、
1. JavaScript界隈の場合は布教意識ありまくりで公式がかなり充実している。
2. 公式は対象技術レベルを想定して書かれている=読んで無理ならどうせ使いこなせない。
3. 公式以外は「ぼくががんばったきろく」を残したい馬鹿ばかりで、間違いが多すぎる。
4. そもそも普通の奴は「ぼくのさいこうのチュートリアル」なんて作らない。
公式のチュートリアルを充実させる方向に参加する。したがって当然非公式サイトはおしなべてゴミ。
5. 本を書いている奴は本で食っている=一線のプログラマではなくただのテクニカルライタであり、
売れない本は書きたくない。よってどうしても後追いになるし、技術レベルも低い。
6. JavaScriptの場合はフレームワークonフレームワークの状態だから、
はっきり言って、構想を聞いて「あ、いいね」とぱっと思えるのでなければ使う必要がない。
だから本来、対象者にはリファレンスしか必要ない。Nodeとかそんな感じでしょ。
というか、自分が知ってるフレームワーク等と比べてみたらいい。
例えばjQueryを使っている奴は公式トップの3例を見て、「素晴らしい」と思えるから使っているわけだろ。
Nodeの場合は公式トップは空で、aboutで鯖を立てる例だけ出しているが、魅力のアピールにはそれで十分なわけだろ。
同様に、reactの場合も公式トップの4例で十分だと思っているからあの構成な訳で、
それで魅力を感じないのであれば使う必要はないし、意味が分からないのなら使いこなせない。 「Reactを学ぶ」とかワケワカランな
スマホだってなんだって説明書見て使ってれば自分にとって十分使いこなせてるでしょ
「Reactのプロ」になる必要なんてないんだから
ただ道具の一つとして自然に使っていけばいいだけ emscripten_sleep() の以下のソース、理解が出来ない。JSに不慣れだから余計。
誰か助けて欲しい。emscripten は、少なくとも asm.js 形式だと、JS から、
JS の emscripten_sleep() 関数を単純に呼び出している。
以下の、{{{・・・}}} の三重括弧や、callback の部分の意味が理解できない。
[x:\yyyy\emsdk\emscripten\1.38.21\src\library_async.js]
mergeInto(LibraryManager.library, {
#if ASYNCIFY
・・・
emscripten_async_resume: function() {
var callback = 0;
___async = 0;
___async_unwind = 1;
while (1) {
if (!___async_cur_frame) return;
callback = {{{ makeGetValueAsm('___async_cur_frame', 8, 'i32') }}};
// the signature of callback is always vi
// the only argument is ctx
{{{ makeDynCall('vi') }}}(callback | 0, (___async_cur_frame + 8)|0);
if (___async) return; // that was an async call
if (!___async_unwind) {
// keep the async stack
___async_unwind = 1;
continue;
}
// unwind normal stack frame
stackRestore({{{ makeGetValueAsm('___async_cur_frame', 4, 'i32') }}});
// pop the last async stack frame
___async_cur_frame = {{{ makeGetValueAsm('___async_cur_frame', 0, 'i32') }}};
}
}, >>762
・・・
emscripten_sleep: function(ms) {
Module['setAsync'](); // tell the scheduler that we have a callback on hold
Browser.safeSetTimeout(_emscripten_async_resume, ms);
},
・・・
} 以下の前提がある時、
callback = {{{ makeGetValueAsm('___async_cur_frame', 8, 'i32') }}};
{{{ makeDynCall('vi') }}}(callback | 0, (___async_cur_frame + 8)|0);
の部分が、何を意味するのか分かる人いない?
---------------------------------------
var Module = {};
Module["asm"] = (function(global, env, buffer) {
"use asm";
var HEAP8 = new global.Int8Array(buffer);
var HEAP16 = new global.Int16Array(buffer);
var HEAP32 = new global.Int32Array(buffer);
var HEAPU8 = new global.Uint8Array(buffer);
・・・・
}
var dynCall_vi = Module["dynCall_vi"] = function() { return Module["asm"]["dynCall_vi"].apply(null, arguments) };
function makeDynCall(sig) {
if (!EMULATED_FUNCTION_POINTERS) {
return 'dynCall_' + sig;
} else {
return 'ftCall_' + sig;
}
} [何をやってるかの自分なりの推定]
例えば、main() 関数の中で、emscripten_sleep(n) を使うと、setTimeout() を使って、
emscripten_async_resume() 関数を、n(ms) 後に起動するようにしておく。そして、
その段階では、main() の後の処理を全て素通りして、main() 関数から return する。
これは、if 文で、label という名称の local 変数の値で場合わけして、goto で色々な
ラベルに飛んでいるような感じ。でも、JS には、goto 文がないので、関数の処理全体を
大体 while(1) 文のブロック中に入れてしまって、必要な時に break する事で、while
ブロックの次の場所に飛ぶようにしてある。そして、そこで label 変数の値で場合分けして、
何らかの処理を行う。実は、この時、main() 関数に割り当てられた識別番号をどこかの
グローバル変数 g_k に残しておく。この識別番号は、0 から割り振られた小さな値で、
どこかの配列 g_func_s[]には、色々な関数の先頭アドレスが入っており、main もその中の
1つとして入っている。例えば、main に割り振られた識別番号が 5 なら、g_funs[5] で
main の関数アドレスが取得できるようになってるらしい。
次に、n(ms) の時間が経過すると、emscripten_async_resume() が呼び出される。この時点では、
main() 関数は実行を終えてしまっているので、何とかして、もう一度 main() 関数を起動しなおして、
上手く、emscripten_sleep() の直後の行にまで戻りたい。そこで、g_k に残された番号を頼りに、
g_func_s[g_k] の関数を起動しなおす。g_func_s[g_k] には、main 関数の先頭アドレスが入ってい
るので、main 関数を再起動することは出来ることは出来る。
で、main をもう一度起動して、なんとかして、emscripten_sleep() の直後の行にまで進む。
これは、変数「label 」に上手く値を入れることで、何とかしているんだと思う。
この時、スタック・ポインタの値も、元に戻す。
STACKTOP が、スタック・ポインタで、HEAP32[] が、CPU 全体のアドレス空間みたいなもの。
大体、HEAP32[STACKTOP] と書くことで、該当のスタックの近くにアクセスできるらしい。 function dynCall_vi(index,a1) {
index = index|0;
a1=a1|0;
FUNCTION_TABLE_vi[index&15](a1|0);
}
var FUNCTION_TABLE_vi = [b2,b2,b2,b2,_main__async_cb,b2,_vfprintf__async_cb,
_fflush__async_cb_2,_fflush__async_cb_1,_fflush__async_cb_3,
_fflush__async_cb,___fflush_unlocked__async_cb,___fflush_unlocked__async_cb_4,
_printf__async_cb,b2,b2]; 単純にスタックを切り替えて該当処理を再開できるようにしてるだけじゃん >>768
おいらは数学主席だが、そんな単純じゃない。
もっと非常に複雑なことをやってる。
>>765
その情報は助かった。自分一人では数ヶ月間は気付く事は出来なかったと思う。 >>768
asm.js は、JSの「subset」とされる。だから、JSでサポートされてないことは、
asm.jsでも本質的には出来ない。JSは、
・sleep()関数が存在せず、wait()関数も今のところサポートされているブラウザが
かなり限定されるので、原則的には、関数の途中で無限ループ以外では停止する
ことは出来ない。
・関数callを使わずに、アセンブラの単純な(大域) jmp のようなことは
出来ない。だから、スタックポインタだけを元に戻しても、命令ポインタ(IP)
を元に戻すことが難しい。
・LLVMでも、原則的にはコードは個別の関数としてだけ作ることが出来て、
関数の外にコードを書くことはおそらく出来ない。
・ただし、LLVMの場合は、longjmp やスタックポインタなどのサポートが
色々と有るのでそのあたりを利用すれば何らかの方法があるかもしれない。
・だから、Emscriptenのemsripten_sleep()は、非常に高度なことをやっており、
「待ちたい時」は、いったんそれまでの呼び出し連鎖の全ての関数を逆に戻って、
「システム」にまで戻る。原則的には、全ての関数は、なんらかのイベント
からスタートしているので、これは、イベント・ハンドラの処理をいったん
終了して、ブラウザに制御を戻すような事になる。
・一定時間が経過すると、設定しておいたresume用のハンドラがシステムによって
起動されるので、そのタイミングで、呼び出し連鎖の全ての関数を再度、
「再起動」する。この仕組みを使わないと「EIP」を元に戻すことが出来ない
ためである。なお、スタックポインタについては、独自のグローバル変数を元に戻す
だけで済む。スタック自体は、巨大な「配列」をCPUのメモリー空間のように
して、スタックポインタに該当する変数を配列の添え字としてアクセスするような
事をしている。 >>770
[補足]
・データ用のスタックポインタは、単純にSTACKTOPという名称のJSの
グローバル変数によって模倣するとする。
・CPUの全アドレス空間は、HEAP32[] という32BIT整数の配列で
模倣するとする。
・その結果、スタック変数(local auto 変数)は、HEAP32[STACKTOP + ofs/4]
のような形式でアクセスできるようになる。
・通常のCPUでは、関数を呼び出した親のコードのアドレスが、スタック上に保存
されたあと、命令ポインタ IP の値が、呼び出し先の関数の先頭アドレスに修正される。
・JSの関数呼び出しも、ブラウザの内部的な変数に「戻りアドレス」が保存されて、
ある意味ではこれとよく似たことは行われていると考えてよい。
・しかし、このスタックは、HEAP32[] や、STACKTOP とはまったく独立した
ブラウザの内部的な領域にある。
・つまり、この「戻り値アドレス」は、HEAP32[]の中には入ってない。
・だから、STACKTOP を元に戻したところで、CPUの場合のように単純にはいかない。
・その結果、関数呼び出し連鎖を全て cancel する動作と、全て call し直して元に戻す
という動作は、STACKTOP の動作とは別に行わなくてはならない。
・ラベル名やラベル番号を指定した大域 goto 命令みたいなものが有れば話は別なのだが、
多分、JS にはそれがないためである。 JSも、全てのコードを一つの関数の中に収めてしまって、
continue label 文や break label 文を使えば、好きなラベルに
jmp 出来る気がする。
もしそうだとすれば、関数の戻り値のラベル番号も、独自スタック
HEAP32[STACKTOP + ofs/4] に保存し、関数 call は、
JS の関数 call を使わずに、continue label / break label
を用い、関数から戻るときは、HEAP32[] から、戻り値の
ラベル番号を取得して、そのラベルに continue label または、
break label を使って jmp すれば、もっとすっきり実装してしまえる
かも知れない。 sleepは全然複雑じゃない
CPUを例に出すのは大間違いsleepしてもその間に別の処理が走るわけではないのだから
スタックの切り替えだなんだのは必要ないしやっていない
ただ処理ループを一旦抜けてsetTimeoutで待って再開してるだけ > CPUを例に出すのは大間違いsleepしてもその間に別の処理が走るわけではないのだから
JavaScriptでsleepを実装すると「その間に別の処理が走ってしまうから」
それを妨害するのが大変なんでしょ >>775
だからそれsleepじゃないよ
sleepはその場で停止して(他にスレッドがないならば)
他の処理に割り込まれないという特徴がある
それを実現できてない >>776
おまえがsleepを分かってないことは分かった >>770
どうもアホがいて空回りしそうだから先に言っておく
> 原則的には、関数の途中で無限ループ以外では停止する
> ことは出来ない。
これがasync/awaitで構文的に緩和されてる。
勿論それでもシングルスレッドだから、
実行中のコンテキスト(スタック等)の切換は行わなければならないが、
async/awaitをサポートした時点でそれはJSエンジン側の仕事になってる。
emscripten自体はasync/awaitの標準化以前から存在するから、
その部分が結果的にポリフィル的になっているのは致し方ない。 ■ このスレッドは過去ログ倉庫に格納されています