web-dev-qa-db-ja.com

JavaScriptが関数の実行を一時停止してユーザー入力を待機する

HTML5キャンバス、JavaScript、XMLを使って一種のゲームを作ろうとしています。質問と回答をXMLファイルに入れることでクイズを作成できるという考え方です。私はすべての質問をループし、それらを提起し、答えの正しさをチェックするメインループを作成しました。今のところ、私は単にアラートとダイアログボックスを使用して質問に答えています問題は、私のメインループが、ゲーム全体を最初から最後までウォークスルーする1つの大きな相互接続された全体であり、アラートボックスが質問やダイアログボックスを表示するのではなく、答え、次々と、ユーザーとの対話が必要です。質問への回答は画面下部のボックスに表示され、ユーザーはクレーンを操作して正しい回答を選択できます。これが私が立ち往生しているメインループからのコードスニペットです:

answer = loadQuestion(i);
            if (answer == "correct") {
                // answered correctly, update scoreArray and load next question
                scoreArray[currentQuestion] = "correct";
                // show 'next'-button and wait for press to continue

            } else {
                // answered incorrectly again, update scoreArray and load next question
                scoreArray[currentQuestion] = "error";
                // show 'next'-button and wait for press to continue

            }

ご覧のとおり、loadQuestionを呼び出しています。これは、質問を即座にロードし、可能な回答を表示し、今のところ、回答を入力できるダイアログボックスをすぐにスローします。この回答が返され、検証されます。

私はすでにクレーンの制御をプログラムしました、ユーザーはすでにそれで箱を拾うことができます。しかし、loadQuestionを呼び出して値を返すことを期待しているため、これは機能しません。クレーンを使用しているプレーヤーから回答が得られるまでメインループを「一時停止」してから続行するにはどうすればよいですか?私はすでに答えをグローバル変数にして、空のwhile answer == ""を持って、答えが値を取得するまで関数をビジー状態に保つことを試みましたが、これはスクリプトをフリーズさせるだけです。また、回答変数のステータスを監視し、間隔をクリアして値を返すために間隔をいじりましたが、関数がすぐに値を返さずに完了するため、単にfalseが返されます。

9
Jort

クレーンを使用しているプレーヤーから回答が得られるまでメインループを「一時停止」してから続行するにはどうすればよいですか?

それを分割することによって。ブラウザでのJavaScriptの唯一の「歩留まり」は、関数を終了させて​​から、後で(setTimeoutsetInterval、ajaxコールバックなどを介して)呼び出されるように調整することです。あなたの場合、コールバックのトリガーは、前の質問に答えるユーザーのアクションであると思う傾向があります。たとえば、回答ボックスのclickハンドラーなど(setTimeoutなど、自動化されています)。

たとえば、次のコードは次のとおりです。

function loopArray(ar) {
    var index;
    for (index = 0; index < ar.length; ++index) {
       doSomething(ar[index]);
    }
}

...次のようにリキャストできます:

function loopArrayAsync(ar, callback) {
    var index;

    index = 0;
    loop();

    function loop() {
        if (index < ar.length) {
            doSomething(ar[index++]);
            setTimeout(loop, 0);
        }
        else {
            callback();
        }
    }
}

2番目のバージョンでは、ループが繰り返されるたびにブラウザに制御が戻ります。 2番目のバージョンはbeforeループが完了したのに対し、最初のバージョンはループが完了したことを返すことに注意することも重要です。 versionは、すべてのループが完了するまで待機します。そのため、2番目のバージョンには、ループが完了したときに呼び出すcallback関数があります。

最初のコードを呼び出すコードは次のようになります。

var a = ["one", "two", "three"];
loopArray(a);
// Code that expects the loop to be complete:
doTheNextThing();
doYetAnotherThing();

...非同期バージョンの使用は次のようになります。

var a = ["one", "two", "three"];
loopArrayAsync(a, function() {
    // Code that expects the loop to be complete:
    doTheNextThing();
    doYetAnotherThing();
});

これを行うと、おそらく closures (上記のloopはクロージャです)を使用していることに気付くでしょう。役に立つ: クロージャは複雑ではない

19
T.J. Crowder

同期はありません。 alertconfirm、およびPromptを除く、ブラウザーJSの入出力ツールを一時停止しました。それらを使用したくないので、次のパターンを試してください。

loadQuestion(i, function(answer) {
   if (answer == "correct") {
            // answered correctly, update scoreArray and load next question
            scoreArray[currentQuestion] = "correct";
            // show 'next'-button and wait for press to continue

        } else {
            // answered incorrectly again, update scoreArray and load next question
            scoreArray[currentQuestion] = "error";
            // show 'next'-button and wait for press to continue

        }
  resumeGameExecution();
});

つまりユーザーがそれに答えると、コールバック関数が実行され、準備ができていることがわかります。

3
zindel

私の理解では、一連の質問をしてから、ドラッグアンドドロップコントロール(クレーン)を使用してユーザーに回答をドロップするように求めるアンケートアプリケーションがあります。

私は正接して、デザインが間違っているようだと言います。 Javascriptはイベントベースであり、ユーザーとの対話のために1つのメインスレッドをループさせると、使いやすさが低下します。スレッドをストールさせる方法は使用しません(Javaでは別名)。 Javascriptはそのようなユースケース向けには書かれていません。アプリケーションは、一部のブラウザーおよびほとんどすべてのパフォーマンスアナライザー(Yslowなど)によって応答しないものとして認識されます。

したがって、内部的にシーケンスであるクラス(question1..2)によって識別されるdivを各質問に提供します。最初は、1つの質問のみが有効化または表示されます。ユーザーが質問に回答したら、有効な質問を有効にします。 (適切なイベント、この場合はおそらくドラッグアンドドロップのドロップイベント)。シーケンシャルなので、ユーザーが質問1に回答したかどうかを確認するだけで、質問2を適切に有効にします。フロー全体はイベント駆動型である必要があります。ここでのイベントは、質問に答えるユーザーです。

2