1

UWA ウィジェット形式を使用して JavaScript ウィジェットを開発しています。残念ながら、これにより私のコードを jsFiddle することはできなくなりますが、詳細にコメントしたので、うまくいけば、かなり簡単な手順に従うことができます。

HighestClass = {};
HighestClass.array = [];
HighestClass.url = "http://our.url.local/frog/pointsByWeek.php?cmd=highestClass&students=";

HighestClass.init = function(groupPrefix) {
    var count = 0;

    /* Using the group prefix, i.e. "CLS 9", from the drop-down box,
        get a list of all of the classes in that year group */

    /* First time round, count the number of groups that match this
        syntax because there are no parameters available to filter
        this API */

    Frog.API.get('groups.getAll',{
        'onSuccess': function(data){
        for (var i = 0; i < data.length; i++) {
            if (data[i].name.indexOf(groupPrefix) != -1)
                count++;
        }
    });

    /* Now that these classes have been counted, run through the API
        call again to push each class ID through to another function */

    var run_through = 0;

    Frog.API.get('groups.getAll',{
        'onSuccess': function(data){
        for (var i = 0; i < data.length; i++) {
            if (data[i].name.indexOf(groupPrefix) != -1) {
                var end = false;

                run_through++;

                /* When it gets to the last class group, i.e. the run_through 
                    variable becomes equal to count, let the getClassPoints
                    function know */

                if( run_through == count )
                    end = true;

                HighestClass.getClassPoints( data[i].name, data[i].id, end );
            }   
        }
        }
    });
}

HighestClass.getClassPoints = function(name, id, end) {
    var list = '';

    /* Using the ID of the class group, create a comma-separated list
        of students for use in our MySQL query */

    Frog.API.get("users.search", {
        "params": {
            "group": id
        },
        "onSuccess": function (data){
            for (var i = 0; i < data.length; i++)
                list += data[i].id + ",";
        }
    });

    /* If the list exists... */
    if( typeof list === "string" && list.length > 0 ) {
        list = list.slice(0,-1);

        /* Run an AJAX call to our PHP script which simply returns an integer
            value of the SUM of reward points earned by that list of students */

        UWA.Data.getJson(HighestClass.url + list, function(res){
            if (res === false || res === "") res = 0;

            /* Push this data into an array of objects alongside the class name */

            var obj = { "name": name, "points": res };
            HighestClass.array.push(obj);
        });
    }

    /* As this function is being called asynchronously multiple times we need to
        determine when the last call is run so that we can deal with our array
        of data. We do this thanks to the count/run_through variables in earlier
        function which will trigger end=true in this function */

    if( end === true )
        HighestClass.display();
}

HighestClass.display = function() {
    /* Once we've put our array of objects together, we need to sort it so that
        the class with the highest number of points are at array entry 0 */

    function compare(a,b) {
        if (a.points < b.points)
            return 1;
        if (a.points > b.points)
            return -1;

        return 0;
    }

    /* IF I PUT AN ALERT HERE, INTERNET EXPLORER WORKS, LOL? */

    HighestClass.array.sort(compare);

    /* We can then display the data of array entry 0 which should be our highest
        point-scoring class */

    $('#display').html( '<h1>' + HighestClass.array[0].name + '</h1><h3>' + HighestClass.array[0].points + '</h3>' );
}

/* equivalent of document ready */
widget.onLoad = function(){
    /* Choose the year group from the drop down box */
    $("select").change(function(){
        var val = $('select option:selected').val();

        $("#display").html('<h1><img width="60" height="60" src="http://logd.tw.rpi.edu/files/loading.gif" />Loading...</h1>');

        HighestClass.init(val);
    });
}

本質的に、スクリプトは次のことを行います。

  1. 各クラス グループの生徒のリストを取得する
  2. PHPスクリプト/MySQLデータベースへのAJAX呼び出しを実行して、それらの学生のポイントの合計を返します
  3. オブジェクトの配列に名前とポイント情報を追加します
  4. 最高得点のクラスが最初の配列エントリになるように、オブジェクトの配列を並べ替えます
  5. クラスの名前と配列エントリ 0 からのポイントを表示します

問題は、(API の制限のため) 私が考えることができる唯一の方法は、非同期 API 呼び出しを実行し、これらから AJAX 呼び出しをチェーンすることです。次に、カウント変数を使用して、最後の非同期呼び出しがいつ行われたかを判断します。

さて、重要なことに、このスクリプトは FireFox で完全に機能します。ただし、Internet Explorer では、スクリプトは「読み込み中」の DIV/画像を表示し、それ以上は実行しません。

奇妙なことalertに、コード (大文字でコメントした場所) に を入れると、Internet Explorer は正しく動作します。

これは同期性とタイミングの問題に違いありませんが、私には経験も知識もありません。

誰でも解決策を提案できますか? 必要に応じて、Hacky で問題ありません。

乾杯、

4

3 に答える 3

2

最初に: /!\ コールバック パターンを使用する場合、コールバック関数で「フロー」を再度開始する必要があります。

非同期とコールバックのアプローチに問題があることがわかります。$.getJSON だけでなく、Frog.API 呼び出しを行うたびに、例:

Frog.API.get("users.search", {
    "params": {
        "group": id
    },
    "onSuccess": function (data){
        for (var i = 0; i < data.length; i++)
            list += data[i].id + ",";
    }
});

ここでは、データを取得し、onSuccess コールバック関数を使用してリストに入れます。私の推測では、この呼び出しも非同期です。この呼び出しに時間がかかりすぎる場合:

 if( typeof list === "string" && list.length > 0 ) {

合格しません。したがって、何も起こらず、ディスプレイは未定義のオブジェクトの値を取得しようとします => エラーが発生し、JavaScript が停止し、ビューが更新されません。リストが取得された後、onSuccess コールバックで getJSON が必要です。次の後に同じ間違いを犯すため、これは役立ちます。

次の例では、ディスプレイを表示するように求めていますが、通話が終了したかどうかはまったくわかりません。最後の呼び出しを要求したという事実は、呼び出しのいずれかが終了したことを意味するものではありません。

if( end === true )
    HighestClass.display();

したがって、次のように追加するだけです。

HighestClass.array.push(obj);

これは $.getJSON 呼び出しにあります。

Ajax 呼び出しは通常非同期であり、問​​題は、サーバーが応答するのを待たずに、現在のフローと同期して表示を更新しようとすることです。 /!\ コールバック パターンを使用する場合、コールバック関数で「フロー」を再開する必要があります。それを使用すると、実行しているコードに、その義務を果たすために必要なすべてのデータがあることを常に確認できます。

PS: 変更されたすべてのコードは次のとおりです。関数の初期化も変更しました。同じことをやり直すために API を再度呼び出す必要はありません。データを2回ループするか、関連するデータのみを配列に入れてからループします。

HighestClass = {};
HighestClass.array = [];
HighestClass.url = "http://our.url.local/frog/pointsByWeek.php?cmd=highestClass&students=";

HighestClass.init = function(groupPrefix) {

    /* Using the group prefix, i.e. "CLS 9", from the drop-down box,
        get a list of all of the classes in that year group */

    Frog.API.get('groups.getAll',{
        'onSuccess': function(data){
        var i = 0,
            l = 0,
            count = 0,
            group = [];
        /* First time round, count the number of groups that match this
            syntax because there are no parameters available to filter
            this API */
        for (i = 0, l = data.length; i < l; i++) {
            if (data[i].name.indexOf(groupPrefix) != -1)
                group.push(data[i]);
        }

        /* Now that these classes have been counted, run through the API
        call again to push each class ID through to another function */
        l = group.length;
        count = l - 1;
        for (i = 0; i < l; i++) {
            // i == count will be true when it is the last one
            HighestClass.getClassPoints( group[i].name, group[i].id, i == count);
        }
    });


}

HighestClass.getClassPoints = function(name, id, end) {

    /* Using the ID of the class group, create a comma-separated list
        of students for use in our MySQL query */
    Frog.API.get("users.search", {
        "params": {
            "group": id
        },
        "onSuccess": function (data){
            var list = '';
            // We have data and build our string
            for (var i = 0; i < data.length; i++)
                list += data[i].id + ",";

            /* If the list exists... */
            if( typeof list === "string" && list.length > 0 ) {
                list = list.slice(0,-1);

                /* Run an AJAX call to our PHP script which simply returns an integer
                    value of the SUM of reward points earned by that list of students */
                UWA.Data.getJson(HighestClass.url + list, function(res){
                    if (res === false || res === "") res = 0;

                    /* Push this data into an array of objects alongside the class name */

                    var obj = { "name": name, "points": res };
                    HighestClass.array.push(obj);


                    /* As this function is being called asynchronously multiple times we need to
                        determine when the last call is run so that we can deal with our array
                        of data. We do this thanks to the count/run_through variables in earlier
                        function which will trigger end=true in this function */

                    if( end === true )
                        HighestClass.display();
                });
            }
        }
    });



}

HighestClass.display = function() {
    /* Once we've put our array of objects together, we need to sort it so that
        the class with the highest number of points are at array entry 0 */

    function compare(a,b) {
        if (a.points < b.points)
            return 1;
        if (a.points > b.points)
            return -1;

        return 0;
    }

    /* IF I PUT AN ALERT HERE, INTERNET EXPLORER WORKS, LOL? */

    HighestClass.array.sort(compare);

    /* We can then display the data of array entry 0 which should be our highest
        point-scoring class */
    if (HighestClass.array.length > 0)
        $('#display').html( '<h1>' + HighestClass.array[0].name + '</h1><h3>' + HighestClass.array[0].points + '</h3>' );
    else
        $('#display').html( '<h1>No data available</h1>' );
}

/* equivalent of document ready */
widget.onLoad = function(){
    /* Choose the year group from the drop down box */
    $("select").change(function(){
        var val = $('select option:selected').val();

        $("#display").html('<h1><img width="60" height="60" src="http://logd.tw.rpi.edu/files/loading.gif" />Loading...</h1>');

        try {
            HighestClass.init(val);
        } catch (e) {
            $("#display").html('<h1>Sorry, an error occured while retrieving data</h1>');
        }
    });
}
于 2013-07-21T23:28:49.400 に答える
1

Ajax 呼び出しがここで非同期であることが原因である可能性が最も高いです。

UWA.Data.getJson(HighestClass.url + list, function(res){
            if (res === false || res === "") res = 0;

            /* Push this data into an array of objects alongside the class name */

            var obj = { "name": name, "points": res };
            HighestClass.array.push(obj);
        });

ajax呼び出しが完了するのを待たない限り、呼び出されたときにHighestClass.array空です。HighestClass.display();ajax 呼び出しを同期にするか、これを Ajax コールバックに入れることができHighestClass.display();ます。

于 2013-07-19T19:32:48.803 に答える