location.href=" 文を続けて使用出来ますか?(2)

[上に] [前に] [次に]
えいちく [E-Mail] 1999/06/04(金) 10:27:23
以前この質問をしたのですが、アドバイスを頂けませんでしたので、もう一度分かり易い形(?)
で再度質問させて頂きたいと思います。

実際にはありえないと思いますが、以下のようにダウンロード操作をループさせる処理を考えます。

<HTML>
<HEAD>
        <TITLE>HREF test</title>
        <META CONTENT="charset=euc-jp">
        <SCRIPT LANGUAGE=JavaScript>
        <!--
        for (i=0; i <= 5; i++) {
                location.href="test.csv";
        }
        // -->
        </SCRIPT>
</HEAD>

<BODY>
        <B>location.href のループテスト。</B>
</BODY>
</HTML>

ところがこれをブラウザで実行すると、ダウンロード用のダイアログボックスがループの回数だけ
出てこなくてはいけない筈ですが、一度しか出てきません。
(多分、最後のループでの location.href="test.csv"; の実行結果だと思います。)

しかし、location.href="test.csv"; の後に
        alert("正常に動作させるための操作です。");
といった行を追加してタイミングを取ると、ループの回数だけダイアログボックスが出るように
なります。

なぜ、上記のコードでは正しく動作しないのでしょうか?
また、JavaScriptでこのような操作を確実に行なうにはどうすればよいでしょうか?
アドバイスお願いします。

動作環境は、Windows NT4.0 + Netscape 4.5 です。

Tmb 1999/06/04(金) 10:49:01
想像なんですが,例えば
location.href='hoge.html';
などのようにダウンロードファイルでない場合は,この命令が実行された
ときには,別のHTMLを読みにいくわけですから,それ以後の命令がなん
であろうとも実行されないのではないでしょうか?
ダウンロードファイルの場合でも同じようなことが起こる可能性はあると
思います。
とりあえず,回避法になりそうなものとしては別ウインドウかフレームか
で,とにかく別のtargetのlocation.hrefを読ませるようにしてみては?
見栄えを考えるなら隠しフレームがいいかもしれません。

それとこの場合,もしかしたら同じ隠しフレームのlocation.hrefを2回
連続で書き換えると,1つ目のロード途中で中断して2つ目を読みにいく
こともあるかもしれません。このときはonLoadだか何かで,読み込みが
終わるまでのループを作っておくのが常道かもしれませんが・・・個人的
には無限ループに陥るケースもないとはいえないので,できればそれぞれ
別のtargetを持たせるのがいいのかも。
#杞憂かもしれませんが。

Tmb 1999/06/04(金) 10:54:16
失礼,現状を読み違えてました。
ループをalertで中断させると正常に読み込めるのであれば,
>それ以後の命令がなんであろうとも実行されない
わけではないですね。

ただ,その後に書いたtargetを指定するのや,ウェイトを
噛ませるのは有効かも。

えいちく [E-Mail] 1999/06/04(金) 14:12:25
やはり、意外と難しそうですね。

試しに異なるブラウザ環境でテストしてみたところ、以下のような結果になりました。
1. Windows NT 4.0 + IE 3.0
   alert()文をループ表示した後、csv ファイルをExcel形式で画面に読み込みました。
2. UNIX (Solaris 2.5) + NN 4.04
   alert()文を、確認ボタンも待たずにループ表示した後、ダウンロードのダイアログボックス
   を表示しました。alert()文による確認ボタンは、ダウンロード操作後、押すようになります。

こんなに動作が異なるとは...。

結局はループの中で、
1. 与えた検索条件によりデータベースを検索し、結果を csv ファイルに出力するCGI スクリプト
   を起動する。
2. 作られた CSV ファイルをダウンロードする。
という操作を行なうために、

                        ...
location.href="search.cgi?"+'$param1'+\"+\"+'$param2'+\"+\"+'$param3';
location.href="http://.../$download_file";
                        ...

という処理を実行させたいだけなのですが...。
(この場合、alert()文などをかませないと、csv ファイルが作られないままダウンロードの
  ダイアログボックスが起動します。)

> ただ,その後に書いたtargetを指定するのや,ウェイトを噛ませるのは有効かも。

ウェイトは試してみましたが、その時の設定では効果がありませんでした。
効果があるとしても、パフォーマンスとの兼ね合いもあるので、あまり長時間の設定は好ましく
ないし、何か簡単で確実な方法はないものかと悩んでおります。

いいアイデアがありましたら、宜しくお願いします。

Tmb 1999/06/04(金) 14:59:16
なるほど。1つのファイルを作成した後で,そのファイルをとなるとさらに
難しそうですね。
ただ思うに,最初のlocation.hrefで呼びだしたURLの読み込み(この場合は
ファイル作成)が完了している/していないに関わらず,次のlocation.href
を実行するところに問題があるような気がしますから,それを判断させる必要
があるのではないでしょうか。

例えば
frameA.location.href='search.cgi?・・・
i=0;
while ((frameA.onLoad=false)&&(i < 10000)){
i++;
}
location.href='test.csv';
なんかではどうですか?
#もちろんiのカウンタは無限ループ対策です。

問題はonLoadの挙動なんですけど。ちゃんとcgiの動作終了を拾ってくれるか。
それが無理なら・・・javascriptでは難しいような気がします。

Tmb 1999/06/04(金) 16:09:25
すみません,onLoadでは拾えなかったですね。勘違いしてました。

IE4ならdocument.readyState='complete'ですか。
それ以外だと・・・う〜ん,lastModifiedを使うとか?

たこすけ 1999/06/04(金) 18:21:40
> 結果を csv ファイルに出力するCGI スクリプト
これの最後にLocationヘッダ吐かせるのじゃ駄目なんでしょうか?

CGIの事よくわかってないけど・・・・^^;

えいちく [E-Mail] 1999/06/04(金) 20:55:07
いろいろなアドバイス、ありがとうございます。

> これの最後にLocationヘッダ吐かせるのじゃ駄目なんでしょうか?

課題としている処理では、データベースを検索して結果を csv ファイルに出力し、それを
ダウンロードするというケースだけでなく、以下のような処理もあります。

1. いくつかの異なる検索条件によりデータベースを検索し、結果を1つの csv ファイルに
   追記出力する。(従って、ループ処理となります)
2. 最終的に作られた CSV ファイルをダウンロードする。

1 の「データベースを検索し、結果を csv ファイルに出力する」という処理を汎用的に
使うために、あえて 2 の「ダウンロード処理」と分けていました。
この場合も、1 の処理を繰り返すと、前の処理がキャンセルされるようで、結果的に最後
の検索条件による検索結果しか csv ファイルには記述されていませんでした。

しかし、他にうまいやり方がなければ、ループさせない場合だけでも回避出来るか試して
みる必要はありそうですね。

Nobu3 1999/06/07(月) 00:34:10
単純に複数のDLを連続して行うなら、
location.hrefではなく、
新しいウィンドウに表示させることでうまく行くみたいです。

for(i=0;i<5;i++){
window.open('hoge.lzh');
}

Tmb 1999/06/07(月) 11:59:03
どうもJavaScriptで解決するのは無理のような気がしますね。
といいつつ,僕もCGIについては,てんで判らないのですが。

ただ,原因はおそらくcsvファイルの書込が終了したかどうかを
チェックせずに次の書込や読込を実行している点にあるような
気がします。掲示板の同時書込を禁止するのと同じルーチンで
防止できるのではないでしょうか。

それと同様な処理を使い回すのであれば,cgi呼びだすときに
処理のやり方を決めるパラメーターを1つ追加して呼びだし,
サブルーチンで処理するなり,ライブラリ(でいいんですかね?
jcode.plみたいなのって)にするなりで,呼びだすcgi側で
行う方がいいように思いますけど。

えいちく [E-Mail] 1999/08/24(火) 21:53:53
質問を投げかけたまま、随分時間が経ってしまいました。
結局、アラート文でタイミングを取る形でひとまず完成という事にしていましたが、
アラート文のOKボタンを押すタイミングが早すぎると、最初のlocation.href=...
の処理がスキップされるというトラブルが発生するため、再度解決策を検討する
必要が出てきました。
根本的な解決策も検討したのですが、ひとまずウェイトを噛ませる事で回避する事
にして、以下の様にコーディングしてみたのですが、ウェイトがforループの最初の
setTimeout()にしか利きません。

        function downLoad(param) {
                location.href="listview_dl.cgi?"+param;
        }


        function test() {
                        ...
                for (i=0; i <= num; i++) {
                        if (init_flag == 0) {
                                setTimeout(downLoad, 3000, 0);
                        } else {
                                setTimeout(downLoad, 3000, 1);
                        }
                }
                        ...
        }

ものの本によると、タイムアウトイベントがアクティブな状態で新しいページに移動すると、
タイムアウトが取り消されると書いてありましたが、location.href=...により新しいページ
に移動したと解釈されて取り消されてしまったのでしょうか?
もしそうであれば、何か回避策はないのでしょうか?
再びアドバイスをお願いします。

Tmb 1999/08/25(水) 10:04:39
setTimeoutは「一定時間後に処理を発生させる」ものであって「一定時間処理待ちにする」ものでは
ないですよね?
だからループでつぎつぎにsetTimeoutが実行され,一定時間後につぎつぎに処理が実行されてるのでは?

現在の時刻を取得して,whileループか何かでその時刻+αの時刻になるまで(判定は == でなく >で)
ウェイトをかけるようにしてみてはどうでしょう?

えいちく [E-Mail] 1999/09/10(金) 17:06:35
>setTimeoutは「一定時間後に処理を発生させる」ものであって「一定時間処理待ちにする」ものでは
>ないですよね?
>だからループでつぎつぎにsetTimeoutが実行され,一定時間後につぎつぎに処理が実行されてるのでは?

そのとおりです。勘違いしていました。

>現在の時刻を取得して,whileループか何かでその時刻+αの時刻になるまで(判定は == でなく >で)
>ウェイトをかけるようにしてみてはどうでしょう?

ウェイトをかけるにしても、sleep() のように関数1つという訳にはいかないのですね。
どうせ手間暇かけるなら、やはりきちんとした対策に取り組もうかと、思い直しています。

そこで改めて質問なんですが、JavaScriptとCGIで、引数以外の唯一(?)の情報共有方法である cookieを
用いてうまくハンドリング出来ないかと思っています。
具体的なイメージは以下のとおりです。

1.JavaScript から "location.href=..."文により、CGI を起動する。
2.起動された CGI の最初で、ある cookie の値を、作業中である事を示す「BUSY」にセットする。
  作業が終了したら、その cookie の値を「DONE」にセットする。
3.JavaScript から、次の "location.href=..."文が実行される前に、2 で設定した cookie を参照し、
  その値「BUSY」の間はループから出られないようにする。
4.cookie の値が「DONE」になるのを待ってループから抜け、次の "location.href=..."文により、CGI
  を起動する。

というものです。
元々 cookie は静的な情報を管理するためのもので、このような利用法はイレギュラーなものだとは
思いますが、他にいい方法が見つからなかったため、実現性を検討中です。
この方法について、問題点等知見のある方がおられましたら、アドバイス頂けますよう、お願い致します。

Nobu3 [E-Mail] [HomePage] 1999/09/11(土) 01:39:06
ループでウェイトを取るのはやめた方がいいでしょう。
「ループという仕事」をしているので、クライアントの負担はかなりのものになるかと(経験者)

1秒ごとに自分を呼び出すくらいでいいのでは?

えいちく [E-Mail] 1999/09/13(月) 19:45:18
アドバイス、ありがとうございます。
早速、注意された点に気を付けながら、cookie による対策を試してみようと思った矢先、
タイマーについて以下のようにコーディングすれば、当初期待したとおりの動きをする
事に気が付きました。

function downLoad(param) {
        location.href="listview_dl.cgi?"+param;
}

function test() {
...
        for (i=0; i <= num; i++) {
                setTimeout(downLoad, 3000 * (i + 1), 1);
        }
        ...
}

結局、ループした数だけウェイトに掛け合わせるという、馬鹿馬鹿しいほど単純な操作で、
すぐに気が付かなかった間抜けさ加減を暴露するようなものですが、多くの方のお手を煩わせた
手前、念のためご報告致します。
ただ実際の処理では、各処理の負荷や、サーバー・回線の混み具合等を考慮した、必要十分な
値を設定しなくてはなりませんが、ほとんどの場合、かなり冗長な処理になってしまうため、
やはり根本的な解決策を見つける必要がありそうです。

えいちく [E-Mail] 2000/01/05(水) 16:19:38
前述の方法でとりあえず仮対応していたのですが、新たな問題が発生しました。
これは複数のデータを一括してダウンロードすると、処理が途中で終わってしまう
場合があるというものです。現象には再現性がなく、同じ操作に対して成功する
場合もあれば、違うデータに対して処理が終わってしまう場合もあります。
現象的にプログラム的なミスではなさそうでしたので、ブラウザのバージョンを
NetScape V4.04からV4.51に上げてみたところ、このトラブルはかなり減りました
が、まだ皆無という訳ではないようです。
この件について、何か知見のある方がおられましたら、是非アドバイス頂けます
よう、お願い致します。

Ichi 2000/01/16(日) 06:28:50
少し興味があります。

私見としては、最初に、csvファイルをCGIを呼び出して少しずつ作って行く
という設計にした時点で、タイミングに悩まされることが決まってしまって
いるような気がします。

JavaScriptで、検索する項目を全てチェックしてから、一括でCGIに
渡し、検索させて、location: で持ってくるというのはどうでしょう。

細かい部分が分かりませんので、はずしていたら済みません。

[上に] [前に] [次に]