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:这里是所有修改的代码。我还修改了你的函数 init。您无需再次调用 API 即可重做相同的事情。只需在数据上循环两次或将唯一相关的数据放在一个数组中,然后循环它。

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

警报“修复”问题的事实确实表明它与时间问题有关。看起来您的函数之一没有及时返回并且没有正确填充数组变量。

尝试将 count 和 end 变量设为全局变量,看看是否有帮助。我认为这与范围有关。

于 2013-07-15T08:26:31.417 回答
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);
        });

并且HighestClass.array在调用时为空,HighestClass.display();除非您等待 ajax 调用完成。您可以使您的 ajax 调用同步或将其HighestClass.display();放在 Ajax 回调中。

于 2013-07-19T19:32:48.803 回答