innerHTMLやinnerTextでの反映タイミングについて教えてください。
JavaScriptでsleep関数の自作テストを行なっている過程で
innerHTMLやinnerTextが即時には反映されない現象に直面しました。
コードを貼り付けておきます。
※htmlとしてIE等のブラウザで動かしてもいいですが、
htaとして実行したほうが簡易で軽くていいと思います。
このコードでは
(1)innerHTML(かinnerText)で「実行中…」を表示
(2)sleep関数を呼ぶ
(3)innerHTML(かinnerText)で「終了」を表示
という、(少なくとも表示部分に関しては)
極めて単純な処理をしています。しかし(1)が反映されません…。
(1)と(2)の間にalertを書いたりするときちんと(1)が表示されます。
よく他言語・フレームワークではflushとかリアルタイム描画等の
コマンドやオプションで対処できるので、JavaScript(JScript)でも
ないものかなぁと思い質問してみることにしました。
質問は以下です
・この現象はなぜ起こるのか。原因説明
・これを回避する方法はあるかないか
・あるのならその方法
明示的なコマンド・オプションでも対症療法でもかまいません。
環境はとりあえずはWinXP・hta(レンダリングエンジン:IE8)で動けばOKです。
よろしくお願いします。
<html>
<body>
<div id="status">sleepテスト</div>
<input type="button" onclick="testAjaxSleep()" value="testAjaxSleep"><br>
<input type="button" onclick="testBusySleep()" value="testBusySleep"><br>
<br>
<script>
var waittime = 3;
function testAjaxSleep() {
document.getElementById("status").innerHTML = "「AjaxSleep」実行中…";
ajaxSleep(waittime);
document.getElementById("status").innerHTML = "AjaxSleep終了";
}
function testBusySleep() {
document.getElementById("status").innerText = "「BusySleep」実行中…";
document.close();
busySleep(waittime);
document.getElementById("status").innerText = "BusySleep終了";
}
function ajaxSleep(sec) {
var stopTime = (new Date()).getTime() + Math.floor(1000 * sec);
var url = "http://www.google.com/?dummy";
var xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
while (stopTime > (new Date()).getTime()) {
xmlHttp.open('GET', url, false);
xmlHttp.send(null);
}
}
function busySleep(sec) {
var stopTime = (new Date()).getTime() + Math.floor(1000 * sec);
while (stopTime > (new Date()).getTime()) {}
}
</script>
</body>
</html>
No.7ベストアンサー
- 回答日時:
お礼書いてくれたので、蛇足となりつつも
AJAXでサーバーの応答待つのは、あまりにも不正確になりがちで、
処理待ちの間ブラウザごとロックするブラウザーもあるそうです。
そこで、HTAでやってるって事なんで、wscriptshellのsleepを使って
もう一つ似たようなやつを↓
(sleep.js)
var parm = WScript.arguments;
if (parm.length > 0) {
WScript.Sleep(parm(0)*1000);
}
を準備して
HTA内からajaxSleep()で呼び出す、
function ajaxSleep(sec){
var WshShell = new ActiveXObject("WScript.Shell");
WshShell.run("wscript sleep.js " + sec , 0 ,true); //同期
WshShell = null;
}
※実際は固定のパス名(sleep.jsの保存場所)も指定しときゃなきゃいけないけど。
おお。おおおおぉおぉ。
きちんと(1)を実行してから(2)で待ち、その後に(3)が表示されることを確認しました。すばらしいです。
通常のWebや他のブラウザでは動かないものの、わたしは「とりあえずはWinXP・htaで動けばOK」というニーズだったので、これを完全にクリアしているわたしの求めていた結論といえます。(もともとの質問とは少しずれましたが)
余談ですが、私はhtaはできればhtaファイルそのもの1ファイルのみで完結するほうが望ましいと思っているため、wscript用に別ファイルを用意するのではなく、実行時にそのファイルを作成し、onunload時に削除するという方法をとろうかと思っています。
意外なことに新たなsleep実装方法を得ることが出来、大きな収穫となりました。ちょっと待っていてよかったです。
ご回答ありがとうございました。
No.6
- 回答日時:
他の言語なら、sleep関数があるから、
これこそ AjaxSleep()関数 だ!
<div id="hoge"></div>
<script type="text/javascript">
function AjaxSleep(sec){
var XHR = new XMLHttpRequest();
XHR.open("GET","sleep.php?timesec=" + sec,false); //同期通信にする!
XHR.send(null);
if(XHR.responseText==="complete") XHR = null;
}
document.getElementById("hoge").innerHTML = "hoge";
//3秒待つ
AjaxSleep(3);
//
document.getElementById("hoge").innerHTML = "fuga";
</script>
</body>
sleep.phpの中で、
<?php
header('Content-Type: text/plain; charset=UTF-8');
if(isset($_GET['timesec'])){
usleep($_GET['timesec'] * 1000000);
}
echo 'complete';
?>
これは…No.1で私が記述した
「指定秒数sleepしてからレスポンスを返すサーバへアクセスする方法」
に該当しますね。
このタイプの擬似sleepがもっともきれいな仕組みで出来そうですよね。
「JavaScript単体で実現させたい」という希望に対応することは、
難しそうだということはわかりました。
サーバーを使用しsleepする方法を検討してみます。
ご回答ありがとうございました。
No.5
- 回答日時:
>待っている間に他の処理をしてもらっては困ります。
はい。
whileでのsleepのエミュレートは「処理をしない」です。
つまり、画面の描画も行いません。
画面の描画という「sleepの処理以外の処理」を行っていませんから、正しい動作です。
なお、「正しい動作」と「期待する動作」は意味が違いますので、あしからず。
将来的にはE4XやGecko定義のJavaScript、JScriptなどでCなどのsleepと同じ物が作られるかもしれませんが、
現段階では他の動作(画面描画)をさせたい場合は、setTimeoutなど、他の処理が出来る方法を使わなければなりません。
ブラウザには処理をさせるが、利用者には処理をさせないというのであれば、
ドキュメント全体で入力を受け付け、sleep中はその処理をキャンセルするしかないですね。
<form onsubmit="return false;">
のような方法です。(他にDOMを使った方法もありますが)
どうしてもsleepを使いたいのであれば、多少強引かもしれませんが、ご参考に。
未検証です。
function testBusySleep() {
document.getElementById("status").innerText = "「BusySleep」実行中…";
setTimeout(function(){
busySleep(waittime);
document.getElementById("status").innerText = "BusySleep終了";
}, 1);
}
>whileでのsleepのエミュレートは「処理をしない」です。
>つまり、画面の描画も行いません。
(2)の最中に画面描画を行なわなくてもまったく問題ありません。希望は(1)を実行してから(2)に進みたいということです。質問はその実現は出来ないのかということだったのですが、それは説明するまでもなくできないということなのでしょうかね。
画面描画を強制的に起こさせようと試行錯誤してみました。
(1)の処理部分に「resizeBy(3, 3)」と書いてみました。すると、ウインドウ枠の変更自体は即時に起こったのですが、内側のレンダリングだけが遅れ、おかしな見た目になりました。それ以外にもいくつか試したのですが解決には至りませんでした…。
ご回答のとおり、(2)にはいる前に(1)の描画を行なうことは出来ないのかもしれませんね。だいぶ諦めがついてきました。
ありがとうございました。
No.4
- 回答日時:
誤解があるように思われますが、現行の JavaScript で sleep() 関数は「作れません」(ActionScript などを併用する試みなどはありますが、今は考えません)。
A;
sleep(10);
B;
C;
と同じことをしたければ、
A;
function callback() {
B;
C;
}
setTimeout(callback, 10 * 1000);
のように後続処理を全てコールバック関数に入れ、setTimeout() で遅延実行します(正確に 10 秒後にはなりませんが、今は問題にしません)。それまで使っていたコンテキスト情報をどのように渡すか、なども工夫して下さい。
要するに、sleep() を持つ言語系なら内部的にやっている継続渡し的なことを、JavaScript では自前で管理しなければならないということです。それゆえ、上から手続きをだらだら並べるのではなく、きちっと処理単位ごとにブロック化(関数化)する必要があります。まあ、この辺はイベント駆動のコードを弄った経験があればすぐに慣れると思いますし、JSDeferred などのライブラリもあります。
> while (stopTime > (new Date()).getTime()) {
言葉が悪いですが、これは一種のブラクラですので、絶対にやらないで下さい。
※余談ながら、HTML4/5 で html 要素、body 要素の開始タグと終了タグは省略可なのでサンプルでは不要です。文法的な意味で絶対に必要なのは title 要素の開始・終了タグです。
※Msxml2.XMLHTTP でバージョンを省略すると 3.0 が使われます。.NET Framework などが入っていれば MSXML 6.0 が入っている可能性が高いと思います。
ご提示いただいた方法は私がNo.1の補足で書いた内容ですね。
# (3)に当たる処理を関数にして(2)でsetTimeoutする
# ということをすれば似た現象を引き起こせると思いますが
# 要件を満たせませんし、そもそも関数の自作でもありません。
今回のサンプルのajaxSleepであればまぁまぁいけていると思っていたのですが、JavaScriptでの完全な「sleep関数の自作」は難しいようですね。
ご回答ありがとうございました。
No.3
- 回答日時:
同期通信はsendを行った後、画面描画や利用者(マウス操作やテキストエリアなどへのキー入力など)の処理を行わずにサーバーからの応答を待ち続けます。
質問文中のコードでは、応答があった直後はまだwhile()の中にあるため、そのまますぐに次のopen(同期通信)を行います。
whileでsleepをエミュレートする方法は、あくまで「一定時間待つ」だけであって、待っている間に何かの処理をする(処理が出来る)という物ではありません。
画面描画や利用者の処理を待つ場合は、いったん関数を抜けるか、alert()などでブラウザに処理を渡す必要があります。
ご回答ありがとうございます。
一点確認させてください。
>whileでsleepをエミュレートする方法は、あくまで「
>一定時間待つ」だけであって、待っている間に
>何かの処理をする(処理が出来る)という物ではありません。
そもそもsleepですので処理を待つことが目的です。
待っている間に他の処理をしてもらっては困ります。
ただし、sleepの前の処理は行なってから
待ちを開始してほしいということです。
(1)-(3)の例で言えば
(1)を行なってから(2)をしてほしいと、当然とも思える
ただそれだけの希望です。
ところが実際には、(1)が反映される前に
(2)に進んでしまっているように見えることが問題なのです。
(1)を画面上に反映させてから(2)に進ませるということを、
提示しているプログラムの機能を損なうことなく実現させることは
事実上不可能だというご回答だと理解してよろしいでしょうか?
よろしくお願いします。
No.2
- 回答日時:
というか、この質問もしかして、
Ajaxリクエストが完了するまで、”実行中”と表示しておいて、
完了したら”完了”と表示させたいだけなのかしら?
だとしたら、変なsleep関数作らなくても、readystateの監視だけでも
でけそうな...
# だとしたら、変なsleep関数作らなくても、
# readystateの監視だけでもでけそうな...
これを読んで、「そういえば普通のajaxアクセスの場合にはonreadystatechangeで表示変更をしたことがあるなぁ」と思って調べてみました。すると、自分の書いたコードで以下の違いがありました。
今回:xmlHttp.open('GET', url, false);
以前:xmlHttp.open('GET', url);
一般的には第3引数を指定しない(もしくはtrueを指定する)から他の処理を継続できる、今回は待たせる為にあえて「false」を指定しているから処理を待ってしまう、という違いがあったことに気がつきました。
この指定の差で画面描画の状態が変わるのだということが分かり、新たな発見が出来、勉強になりました。
ありがとうございました。
No.1
- 回答日時:
この現象はなぜ起こるのか。
=>あなたの作られたsleep関数の中で、無意味にxmlHttp.send(null)
を繰り返しているため、スクリプトエンジンはinnerHTMLの書き換え
指示を出す暇が無いのです。alertを入れると中断するのでその隙に
innerHTMLを書き換えることが出来ます。
これを回避する方法はあるかないか
=>window.setTimeout/window.clearInterval、とか
window.setInterval/window.clearInterval を
使えば無駄なループを実行しなくても出来ます。
あるのならその方法
省略:上のsetTimeoutとかでNET検索してみてください。
この回答への補足
> =>window.setTimeout/window.clearInterval、とか
> window.setInterval/window.clearInterval を
> 使えば無駄なループを実行しなくても出来ます。
もともとやりたかったことはsleep関数の自作です。sleep関数とは、それを(2)で呼び出すことで(3)以降の処理を待たせることができる関数です。
(1)や(3)の処理部分を書き換えなければならないのであればそもそも要件を満たしていないことになります。
私が掲げた2つの関数はこの要件を満たしています。
(3)に当たる処理を関数にして(2)でsetTimeoutするということをすれば似た現象を引き起こせると思いますが要件を満たせませんし、そもそも関数の自作でもありません。
sleep関数の自作は、おそらくsetTimeoutやsetIntervalでは実現できないのではないかと思います。sleepの自作例として、ここで掲げた2つの方法がよくネット上で見かけた方法です。
また、他にも別ページをダイアログに表示させ指定秒後に閉じることで待たせる方法や、Javaアプレットを使用する方法や指定秒数sleepしてからレスポンスを返すサーバへアクセスする方法などをネット上で見つけましたが、今回はJavaScript単体で実現させたいと思っているためそのような方法は今回はNGです。
もしも、ここに掲げている2つの自作sleep関数以外の方法でsleepが実現できるのであればそれも教えていただきたいです。
よろしくお願いします。
ご回答ありがとうございます。
>あなたの作られたsleep関数の中で、無意味にxmlHttp.send(null)
>を繰り返しているため、スクリプトエンジンはinnerHTMLの書き換え
>指示を出す暇が無いのです。
busySleepはその名のとおりCPUリソースを使用し続ける関数です。busySleepについてであればそうかもしれません。
しかしajaxSleepはレスポンス受信を待つ為、(マシン性能や回線速度にもよるとは思いますが)CPUはほとんど消費しません。そのajaxSleepについても同じなわけです。
CPUはほとんど消費していなくても「指示を出す暇が無い」のでしょうか?そういうものなのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript javascriptでテーブルに追加した項目のid追加してローカルストレージを操作したい 5 2023/01/01 15:52
- JavaScript 1日1回引けるJavaScriptおみくじについて 1 2022/12/12 22:28
- JavaScript javascriptのちょっとした動作不良(原因は突き止めたのですが) 1 2023/06/15 19:58
- JavaScript コードレビューをお願いします。 1 2022/07/16 05:38
- JavaScript 画像の表示位置 3 2022/12/23 08:25
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- JavaScript 以前の質問だと、どの条件でも配列が表示されてしまいます。 1 2022/07/09 11:40
- JavaScript javascript作成してます。ラジオボタンで判定するコードを書いてます。 1 2023/07/18 11:03
- JavaScript ①入力フォーム→②確認表示画面→③送信完了画面のコードを書いているのです、 入力フォームから受け取っ 2 2022/05/10 16:45
- JavaScript GoogleChart 階層ごとのブロックの長さを個別に設定したい 1 2022/07/06 14:27
このQ&Aを見た人はこんなQ&Aも見ています
-
10代と話して驚いたこと
先日10代の知り合いと話した際、フロッピーディスクの実物を見たことがない、と言われて驚きました。今後もこういうことが増えてくるのかと思うと不思議な気持ちです。
-
秘密基地、どこに作った?
小さい頃、1度は誰もが作ったであろう秘密基地。 大人の今だからこそ言える、あなたの秘密基地の場所を教えてください!
-
初めて自分の家と他人の家が違う、と意識した時
子供の頃、友達の家に行くと「なんか自分の家と匂いが違うな?」って思いませんでしたか?
-
この人頭いいなと思ったエピソード
一緒にいたときに「この人頭いいな」と思ったエピソードを教えてください
-
うちのカレーにはこれが入ってる!って食材ありますか?
カレーって同じルーから作っても、家庭によって入っているものや味が微妙に違っていて面白いですよね! 「我が家のカレーにはこれが入ってるよ!」 という食材や調味料はありますか?
-
innerHTML実行後のイベント
JavaScript
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/22】このサンタクロースは偽物だと気付いた理由とは?
- ・お風呂の温度、何℃にしてますか?
- ・とっておきの「まかない飯」を教えて下さい!
- ・2024年のうちにやっておきたいこと、ここで宣言しませんか?
- ・いけず言葉しりとり
- ・土曜の昼、学校帰りの昼メシの思い出
- ・忘れられない激○○料理
- ・あなたにとってのゴールデンタイムはいつですか?
- ・とっておきの「夜食」教えて下さい
- ・これまでで一番「情けなかったとき」はいつですか?
- ・プリン+醤油=ウニみたいな組み合わせメニューを教えて!
- ・タイムマシーンがあったら、過去と未来どちらに行く?
- ・遅刻の「言い訳」選手権
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
JSPの処理の途中で、JavaScript...
-
if(1){...}とはどういうことで...
-
初心者です。gulpでコンパイル...
-
JavaScriptで、実行するたび値...
-
VB.NET初心者です。
-
VBA SORT Applyでエラー
-
VB.netでタイマーがスタートし...
-
ラベルの色がかわってくれない
-
以下のコードを実行しても、オ...
-
Excelのマクロ一括実行ができな...
-
〔Excel:VBA〕マクロの実行が異...
-
VBAによる第3、4水準文字の判定...
-
JavaScriptで ブラウザの閉じる...
-
エクセル 半角英数6文字以上 ...
-
htmlのfileタグに自動で値を入...
-
Session切れ前にWarningメッセージ
-
関数を最終行までコピー
-
gas 全角数字を半角数字に変換
-
C#の質問です。
-
変換テーブルを使った、文字列...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
JSPの処理の途中で、JavaScript...
-
if(1){...}とはどういうことで...
-
PowerPointで時計表示
-
C#でボタン名を変更しても動く
-
デザイン時のVisible=Falseは実...
-
初心者です。gulpでコンパイル...
-
jQuery ui Datepicker 明日以降...
-
VBA SORT Applyでエラー
-
〔Excel:VBA〕マクロの実行が異...
-
innerHTMLなどの反映タイミング
-
リクエスト結果が一瞬しか表示...
-
1つのVBAコードをすべてのコア...
-
VBA ステータスバー DoEvents
-
VB.netでタイマーがスタートし...
-
javascriptで最初のところに戻...
-
Excelのマクロ一括実行ができな...
-
既存のwebサイトで、ローカルの...
-
JavaScriptでショートカットキ...
-
ラベルの色がかわってくれない
-
eval()の危険性の具体例を教え...
おすすめ情報