简体   繁体   English

使用jQuery和Node在DOM上填充数据的最佳方法

[英]Best way to populate data on DOM using jQuery and Node

I am using Node's Socket.io to push data from server to client browser. 我正在使用Node的Socket.io将数据从服务器推送到客户端浏览器。 On client I use jQuery to populate the returned rows in the DOM. 在客户端我使用jQuery填充DOM中返回的行。

Below the code snippet I use to populate the data returned by Socket.io. 我在代码片段下面用来填充Socket.io返回的数据。

var OverSpeedAlerts = [];
var TripCancellation = [];
var GeofenceInOutAlerts = [];
var ScheduleOverstay = [];
var UnSchduledOverstay = [];
var SkippedBusStop = [];
var TripDelayAlert = [];

var SkippedUnplannedAlert = [];
var DelayStartEndAlert = [];
var RouteDeviatedAlert = [];

var MultipleBusEntry = [];

Declaring the prototype: 声明原型:

Array.prototype.inArray = function (comparer) {
    for (var i = 0; i < this.length; i++) {
        if (comparer(this[i])) return true;
    }
    return false;
};

// adds an element to the array if it does not already exist using a comparer 
// function
Array.prototype.pushIfNotExist = function (element, comparer) {
    if (!this.inArray(comparer)) {
        this.unshift(element);
    }
};

Processing the data recieved from socket: 处理从套接字收到的数据:

if (typeof io !== 'undefined') {
    var pushServer = io.connect('http://SomeIP:3000');
    pushServer.on('entrance', function (data) {
        var rows = data.message;
        var NumberOfRows = rows.length;
        $('#notifications').html(NumberOfRows);
        // console.log(rows);
        OverSpeedAlerts = [];
        TripCancellation = [];
        GeofenceInOutAlerts = [];
        ScheduleOverstay = [];
        UnSchduledOverstay = [];
        SkippedBusStop = [];
        TripDelayAlert = [];

        SkippedUnplannedAlert = [];
        DelayStartEndAlert = [];
        RouteDeviatedAlert = [];

        var MultipleBusEntry = [];
        for (var i = 0; i < rows.length; i++) {
            if (rows[i].alert_type == 'overspeed') {
                OverSpeedAlerts.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'trip_cancellation') {
                TripCancellation.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Geofence-In' || rows[i].alert_type === 'Geofence-Out') {
                GeofenceInOutAlerts.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Scheduled-Overstay') {
                ScheduleOverstay.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Unscheduled-Overstay') {
                UnSchduledOverstay.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Skipped Unplanned' || rows[i].alert_type == 'Skipped-Busstop') {
                SkippedBusStop.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Delay Start' || rows[i].alert_type == 'Delay End') {
                TripDelayAlert.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Route Deviated') {
                RouteDeviatedAlert.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }
            else if (rows[i].alert_type == 'Multiple Bus Entry') {
                MultipleBusEntry.pushIfNotExist(rows[i], function (e) {
                    return e.device_id === rows[i].device_id && e.alert_gen_date_time === rows[i].alert_gen_date_time;
                });
            }

        }
        CreateOverSpeedGrid();
        CreateTripCancellation();
        CreateGeofenceGrid();
        CreateScheduleOverstayGrid();
        CreateUnSchduledOverstayGrid();
        CreateTripDelayGrid();
        CreateSkippedBusStop();
        CreateRouteDeviationAlert();
        CreateMultipleBusEntry();
    });
    pushServer.on('end', function (socket) {

    });
}

One of the above functions are as below . 上述功能之一如下 Rest are the similar function filling data in other parts of DOM. Rest是在DOM的其他部分填充数据的类似函数。

function CreateOverSpeedGrid() {
    $('#tabs ul').find('a:contains("Overspeed Alerts")').html('OverSpeed Alerts(' + OverSpeedAlerts.length + ')');
    if (OverSpeedAlerts.length != 0) {
        $('#notifyOverspeed table').html('');
        $('#notifyOverspeed table').append('<tr class="ui-widget-header"> <th> Depot </th> <th> Route </th> <th> Schedule </th> <th> Trip Number </th><th>Trip Direction</th> <th> Alert Summary</th> <th> Alert Details </th> <th> Generated On </th> </tr>'); //new Date([UNIX Timestamp] * 1000);
        for (var i = 0; i < OverSpeedAlerts.length; i++) {
            $('#notifyOverspeed table').append('<tr> <td>' + OverSpeedAlerts[i].depot_name + '</td> <td>' + OverSpeedAlerts[i].route_name + '</td> <td>' + OverSpeedAlerts[i].schedule_no + '</td> <td>' + OverSpeedAlerts[i].trip_number + ' </td> <td>' + OverSpeedAlerts[i].trip_direction + '</td><td> ' + OverSpeedAlerts[i].alert_sub + ' </td> <td title="' + ConvertToValidTooltip(OverSpeedAlerts[i].alert_msg) + '" style="text-decoration:underline;cursor:pointer;"> ' + "Place mouse pointer to view message" + ' </td> <td>' + new Date(OverSpeedAlerts[i].alert_gen_date_time * 1000) + ' </td> </tr>');
        }
    }
}

The above code works fine. 上面的代码工作正常。 BUt the problem is that due to so many push messages being received every 10 seconds from socket the browser is not able to process so much data and hangs up. 问题是,由于从套接字每隔10秒收到如此多的推送消息,浏览器无法处理如此多的数据并挂起。

is there any better way to do it?? 有没有更好的方法呢?

I see the following problems in this code: 我在这段代码中看到以下问题:

  1. You update your table by manipulating the document multiple times. 您可以通过多次操作文档来更新表。 It is better for performance to update the DOM in one operation. 在一次操作中更新DOM的性能更好。 There's a Google article about this. 有关于此的Google文章 So something like: 所以类似于:

     function CreateOverSpeedGrid() { $('#tabs ul').find('a:contains("Overspeed Alerts")').html('OverSpeed Alerts(' + OverSpeedAlerts.length + ')'); if (OverSpeedAlerts.length != 0) { var html = []; html.push('<tr class="ui-widget-header"> <th> Depot </th> <th> Route </th> <th> Schedule </th> <th> Trip Number </th><th>Trip Direction</th> <th> Alert Summary</th> <th> Alert Details </th> <th> Generated On </th> </tr>'); //new Date([UNIX Timestamp] * 1000); for (var i = 0; i < OverSpeedAlerts.length; i++) { html.push('<tr> <td>' + OverSpeedAlerts[i].depot_name + '</td> <td>' + OverSpeedAlerts[i].route_name + '</td> <td>' + OverSpeedAlerts[i].schedule_no + '</td> <td>' + OverSpeedAlerts[i].trip_number + ' </td> <td>' + OverSpeedAlerts[i].trip_direction + '</td><td> ' + OverSpeedAlerts[i].alert_sub + ' </td> <td title="' + ConvertToValidTooltip(OverSpeedAlerts[i].alert_msg) + '" style="text-decoration:underline;cursor:pointer;"> ' + "Place mouse pointer to view message" + ' </td> <td>' + new Date(OverSpeedAlerts[i].alert_gen_date_time * 1000) + ' </td> </tr>'); } // Change the rows in one operation. $('#notifyOverspeed table').html(html.join('')); } } 
  2. The inArray method you add to Array has to scan the whole array before determining that an element is not already in the array. 添加到ArrayinArray方法必须先扫描整个数组,然后才能确定元素是否已存在于数组中。

    Ideally, this filtering would be done at the sending end. 理想情况下,此过滤将在发送端完成。 This would be best. 这是最好的。 However, maybe you are using third party data that cannot be filtered at the source, so... 但是,您可能正在使用无法在源头过滤的第三方数据,因此......

    There is a way to do better. 有一种方法可以做得更好。 If order is important, you could still use arrays to store your objects. 如果顺序很重要,您仍然可以使用数组来存储对象。 Then you could use an object created with Object.create(null) to serve as an associative array only to record whether you've seen an object or not. 然后,您可以使用Object.create(null)创建的对象作为关联数组, 用于记录您是否已经看过对象。 So something like: 所以类似于:

     var OverSpeedAlerts = []; var OverSpeedAlertsSeen = Object.create(null); for (var i = 0; i < rows.length; i++) { var row = rows[i]; var key = row.device_id + row.alert_gen_date_time; if (row.alert_type == 'overspeed' && !OverSpeedAlertsSeen[key]) { OverSpeedAlertsSeen[key] = true; OverSpeedAlerts.push(row); } } 

    I've used this method more than once but the code above is not tested. 我不止一次使用过这种方法,但上面的代码没有经过测试。 Typos or brainos may lurk in there. 错字或脑袋可能潜伏在那里。 In this example the key is computed once for all types of alerts. 在此示例中,为所有类型的警报计算一次密钥。 Looking at your code it looked like all your alerts were compared on device_id and alert_gen_date_time so generating the key once for each item in the array is correct. 查看代码,看起来所有警报都在device_idalert_gen_date_time上进行了比较,因此为数组中的每个项生成一次密钥是正确的。

    How to generate they key depends on the possible values of row.device_id and row.alert_gen_date_time . 如何生成密钥取决于row.device_idrow.alert_gen_date_time的可能值。 You might need a separator to avoid possible ambiguities. 您可能需要一个分隔符以避免可能的歧义。 For instance, in a case I worked on, I had to combine values where all the letters of the alphabet were valid. 例如,在我工作的情况下,我必须组合字母表中所有字母都有效的值。 So without a separator there would be no way to distinguish "ab" + "cd" from "a" + "bcd" from "abc" + "d" . 因此,如果没有分隔符,就无法区分"ab" + "cd""a" + "bcd""abc" + "d" I used a separator that could not appear in the values to build the key: so "ab@cd" , "a@bcd" , "abc@d" . 我使用了一个不能出现在值中的分隔符来构建密钥:所以"ab@cd""a@bcd""abc@d"

    It would also be possible to use an associative array of associative arrays to do the check but I'm not convinced that it would yield a major speed improvement. 也可以使用关联数组的关联数组来进行检查,但我不相信它会产生很大的速度提升。 It would certainly make the code more complex. 它肯定会使代码更复杂。

I can think of other changes that could be made to improve speed but I don't think they could provide substantial gains. 我可以想到可以提高速度的其他变化,但我认为它们不能提供实质性的收益。

Not knowing the details of your app, I'm going to work with the assumption that you need all of that data in the same interface, rather than being able to split it up between, I dunno, tabs or pages or what have you. 不知道你的应用程序的细节,我将假设你需要在同一个界面中的所有数据,而不是能够在它之间拆分,我不知道,标签或页面或你有什么。

If you find it's too much data, presumably your messages don't cycle through so quickly that every 10 seconds it's a whole new batch of data... you likely have longer lived messages sitting in there, being deleted and re-created every 10 seconds. 如果你发现它的数据太多,大概你的消息不会如此迅速地循环,每10秒它就是一整批新数据...你可能有更长时间的消息存在,被删除并每10个重新创建一次秒。

If you instead changed it so that each update contained only changes , eg a new total per list, and then rows to be added and rows to be deleted, you'd likely dramatically improve your performance, and then you could run a full update every, i dunno, 5 minutes (or 15 minutes, or 60 minutes, whatever you feel your app can tolerate) just to make sure you don't get out of sync. 如果您改为更改它,以便每个更新仅包含更改 ,例如每个列表的新总计,然后要添加的行和要删除的行,您可能会显着提高性能,然后您可以每次运行完整更新,我不知道,5分钟(或15分钟,或60分钟,无论你觉得你的应用程序可以容忍),只是为了确保你不会失去同步。

This is almost exactly one of the methods used in video compression, just record the changes from frame to frame, then every so often use a keyframe for error correction. 这几乎就是视频压缩中使用的方法之一,只是记录帧之间的变化,然后经常使用关键帧进行纠错。

If you do this, you could eliminate your pushifnotexists step, just loop directly through your response data and update the table all in the same step. 如果这样做,您可以消除pushifnotexists步骤,直接循环遍历您的响应数据并在同一步骤中更新表。

This is not entirely finished (some repetitive typing is missing at the dom updates) I have eliminated your need for the array prototypes, and made a lookupCache for items allready in the list 这还没有完全完成(在dom更新时缺少一些重复的输入)我已经消除了对数组原型的需求,并为列表中的所有项目创建了一个lookupCache

The updatedom method is an altered version of the one you had, and youll have to re-write the others you used. updatedom方法是您所拥有的版本的更改版本,您必须重新编写您使用的其他版本。

At most parts of the code i added some explination on whats going on and why. 在代码的大多数部分,我添加了一些关于最新进展的原因和原因。 The dom update part can still be made faster, but i expect only rending the new part and updating the dom as a whole will be sufficient, while still making the code understandable and keeping it (relatively) smallish :D, its quite a lot... dom更新部分仍然可以更快,但我希望只更新新部分并更新dom作为一个整体将是足够的,同时仍然使代码可理解并保持它(相对)小:D,它相当多。 ..

There is one confusing thing in the code you provided tho. 你提供的代码中有一个令人困惑的事情。 Initailly you declare the lists (var OverSpeedAlerts etc.) but then inside the processing method for the data received you re-set them to empty array's. 最初你声明了列表(var OverSpeedAlerts等),但是在接收到的数据的处理方法中,你将它们重新设置为空数组。 Was it: 1. your intention to keep the previous dom elements but try to optimize 2. your intention to replace everything with the new data 3. add only the new data to the existing data (which is what this code does) 是它:1。你打算保留以前的dom元素,但试图优化2.你打算用新数据替换所有内容3.只将新数据添加到现有数据(这是代码的作用)

Either case the comments in the code will explain where and how you can optimize your existing code if you wish to do so. 无论哪种情况,代码中的注释都将说明如果您希望优化现有代码的位置和方式。 (most of it will be the single dom update tho) but the filtering will help especially on big lists. (大多数将是单个dom更新)但过滤将特别有助于大型列表。

var io /*some lib*/, pushServer, alertTypes, alterTypesMapping, $notifications, lookupCache;

//i use the -Length fields to store the "previous" length, so i know if the dom needs updating at all
// and what part is new, no need to re-render perfectly valid html
alertTypes = {
    OverSpeedAlerts: [],
    OverSpeedAlertsLength: 0,
    TripCancellation: [],
    TripCancellationLength: 0,
    GeofenceInOutAlerts: [],
    GeofenceInOutAlertsLength: 0,
    ScheduleOverstay: [],
    ScheduleOverstayLength: 0,
    UnSchduledOverstay: [], //scheduled? sorry ide with spelling check
    UnSchduledOverstayLength: 0,
    SkippedBusStop: [],
    SkippedBusStopLength: 0,
    TripDelayAlert: [],
    TripDelayAlertLength: 0,
    SkippedUnplannedAlert: [],
    SkippedUnplannedAlertLength: 0,
    DelayStartEndAlert: [],
    DelayStartEndAlertLength: 0,
    RouteDeviatedAlert: [],
    RouteDeviatedAlertLength: 0
};

//mapping from types to their lists (some types map to the same list)
alterTypesMapping = {
    'overspeed': 'OverSpeedAlerts',
    'trip_cancellation': 'TripCancellation',
    'Geofence-In': 'GeofenceInOutAlerts',
    'Geofence-Out': 'GeofenceInOutAlerts',
    'Scheduled-Overstay': 'ScheduleOverstay',
    'Unscheduled-Overstay': 'UnSchduledOverstay',
    'Skipped Unplanned': 'SkippedBusStop',
    'Delay Start': 'TripDelayAlert',
    'Delay End': 'TripDelayAlert',
    'Route Deviated': 'RouteDeviatedAlert',
    'Multiple Bus Entry': 'MultipleBusEntry'
};

//cache dom lookup
$notifications = $('#notifications');

//we serialize the relevant message parts into an unique id, used for de-duping
//<id> => <alert_type>|<device_id>|<alert_gen_date_time>
lookupCache = {};

function process_data (data) {
    var i, l, rows, id;
    rows = data.message;
    l = rows.length;

    //update dom row count
    $notification.html(l);

    for (i=0; i<l; ++i) {    //caching length in l, ++i is faster than i++
        id = rows[i].alert_type + '|' + rows[i].device_id + '|' + rows[i].alert_gen_date_time;
        if (!lookupCache[id]) {
            lookupCache[id] = 1;    //set it to truthy so next time around its there
            //not in cache push it to the relevant list
            //you used unshift here, that's essentially moving all other elements in the list one spot and
            //adding the new one at index 0 (speed O(n) eg increases with more elements in the list)
            //instead you can push the new element to the end, (speed O(1) constant speed)
            // and when iterating the list doing that in reverse
            alertTypes[alterTypesMapping[rows[i].alert_type]].push(rows[i]);
        }
    }
    updateDom();
}

function updateDom () {
    var keys, i, l, html;

    //here we check all length fields in the alertTypes and see if the actual list length
    //is greater than their -Length
    //if so we update the relevant dom

    keys = Object.keys(alertTypes);
    for (i=0, l=keys.length; i<l; ++i) {
        //skip the -Length keys
        if (keys[i].match('Length')) {
            continue;
        }
        //please add a data-type="<type>" to the a's, so much better to lookup by attribute instead of text matching content
        $('#tabs ul a[data-type="' + keys[i] + '"]').html(keys[i] + '(' + alertTypes[keys[i] + 'Length'] + ')');

        //since well only update the dom, i presume at this point there is a dom with the table with headers
        //(use thead and th for this please)
        //(and use tbody for a table's body)
        //now we iterate the new elements (from list.length back to key-Length)
        //j starts at the length of the list, and ends at m, the previous length
        //counting backwards
        html = [];
        for (j=alertTypes[keys[i]].length, m=alertTypes[keys[i] + 'Length']; j>m; --j) {
            //array join is almost always faster than string concatenation
            //since strings are not mutable in js (eg. you create a new string every +)
            html.push([
                '<tr>',
                    '<td>',
                        alertTypes[keys[i]].depot_name,
                    '</td>',
                    '<td>',
                        alertTypes[keys[i]].route_name,
                    '</td>',
                    '<td>',
                        alertTypes[keys[i]].schedule_no,
                    '</td>',
                    '<td>',
                        alertTypes[keys[i]].trip_number,
                    '</td>',
                    '<td>',
                        alertTypes[keys[i]].trip_direction,
                    '</td>',
                    '<td>',
                        alertTypes[keys[i]].alert_sub,
                    '</td>',
                    '<td ',
                       'title="',
                            ConvertToValidTooltip(alertTypes[keys[i]].alert_msg),
                        '" style="text-decoration:underline;cursor:pointer;">Place mouse pointer to view message',
                    '</td>',
                    '<td>',
                        new Date(OverSpeedAlerts[i].alert_gen_date_time * 1000),
                    '</td>',
                '</tr>'
            ].join(''));
        }
        //and finally we update the key-Length so next time well only add what is newer than what we are about to add
        alertTypes[kesy[i] + 'Length'] = alertTypes[keys[i]].length;
        //get the dom element we have to update
        $('#' + keys[i] + ' tbody').prepend(html.join(''));
    }
}

if (io !== undefined) {   //no need for typeof when checking undefined, check undefined directly with equality (eg. undefined === undefined)
    pushServer = io.connect('http://SomeIP:3000');
    pushServer.on('entrance', process_data);
}

The costly operations are DOM manipulations. 昂贵的操作是DOM操作。

You can improve themby providing your DOM string in one shot, without invoking append multiple time. 您可以一次性改进提供DOM字符串的内容,而无需多次调用追加。 The way you select your DOM nodes is also very important. 选择DOM节点的方式也非常重要。

An example: 一个例子:

function CreateOverSpeedGrid() {
  // Use an ID if possible. It's the fastest way to select DOM nodes. After you can use css classes, or dom custom attributes (data-***). Using contains is very slow.
  $('#overspeed_alerts').html('OverSpeed Alerts(' +  OverSpeedAlerts.length + ')');
  if (OverSpeedAlerts.length != 0) {
      // Fast HTML string: using an array is better than concatenating multiple strings.
      var content = ['<tr class="ui-widget-header"> <th> Depot </th> <th> Route </th> <th> Schedule </th> <th> Trip Number </th><th>Trip Direction</th> <th> Alert Summary</th> <th> Alert Details </th> <th> Generated On </th> </tr>'];
      for (var i = 0; i < OverSpeedAlerts.length; i++) {
        // optimize by accessing your item in array only once.
        var alert = OverSpeedAlerts[i];
        content.push('<tr> <td>', 
            alert.depot_name, 
            '</td> <td>', 
            alert.route_name,
            '</td> <td>',
            alert.schedule_no,
            '</td> <td>',
            alert.trip_number,
            '</td> <td>,
            alert.trip_direction,
            '</td><td> ',
            alert.alert_sub,
            '</td><td title="',
            ConvertToValidTooltip(alert.alert_msg),
            '" style="text-decoration:underline;cursor:pointer;">Place mouse pointer to view message </td><td>',
            new Date(alert.alert_gen_date_time * 1000),
            '</td> </tr>'];
      }
      // Do not select multplie time your table node: it better to store it in a variable.
      $('#notifyOverspeed table').html(content.join(''));
   }
}

Only two DOM access in this solution, instead of N+4 in your first implementation (N is the length of OverSpeedAlerts array. 此解决方案中只有两个DOM访问,而不是第一个实现中的N + 4(N是OverSpeedAlerts数组的长度。

You can also improve the pushIfNotExist method, which is also very time-consuming in my opinion. 您还可以改进pushIfNotExist方法,这在我看来也非常耗时。 I suggest to use a hash in addition to your array, and to use as hash key which is a join between "alert_gen_date_time" and "device_id" : 我建议除了你的数组之外还使用哈希,并使用哈希键作为"alert_gen_date_time""device_id"之间的连接:

// use hash in addition to your array
OverSpeedAlerts = [];
var existingOverSpeedAlerts = {};

for (var i = 0; i < rows.length; i++) {
   // optimize access to row
   var row = rows[i];
   if (row.alert_type == 'overspeed') {
       // join device_id and alert_gen_date_time
       var key = row.device_id + '_' + row.alert_gen_date_time;
       // existence check ! very efficient.
       if (!(key in existingOverSpeedAlerts )) {
          // does not exist yet: adds it, and update your hash.
          existingOverSpeedAlerts[key] = row;
          OverSpeedAlerts.push(row);
       }
    }
    ...

With this, there is no more need to check if the alert is already in the array, because the language test it for you. 有了这个,就不再需要检查警报是否已经在数组中,因为语言会为您测试。 No need for inArray and pushIfNotexist anymore ! 不再需要inArraypushIfNotexist了!

You can also factorize your code by dynamically choosing your hash, depending on the alert_type. 您还可以通过动态选择哈希来分解代码,具体取决于alert_type。 It will not make your code fast, but just more readable (which is also valuable !) 它不会使你的代码更快,但更具可读性(这也很有价值!)

Something like : 就像是 :

if (typeof io !== 'undefined') {
    var pushServer = io.connect('http://SomeIP:3000');
    pushServer.on('entrance', function (data) {
        var rows = data.message;
        var NumberOfRows = rows.length;
        $('#notifications').html(NumberOfRows);

        var alerts = {}; 
        var keys = {};

        // reuse NumberOfRows  here
        for (var i = 0; i < NumberOfRows ; i++) {
          // optimize access to row
          var row = rows[i];
          var type = row.alert_type;

          // add here specificities relative type aggregation
          if (type === 'Geofence-In' || type === 'Geofence-Out') {
            type = 'Geofence-Inout';
          } else if (type === 'Skipped Unplanned' || type === 'Skipped-Busstop') {
            type = 'SkippedBusStop';
          } else if (type === 'Delay Start' || type === 'Delay End') {
            type = 'TripDelayAlert';
          }

          // first alert of a kind !
          if (!(type in alerts)) {
            // init your alert specific array and key hash
            alerts[row.alert_type] = [];
            keys[row.alert_type] = {};
          }

          // join device_id and alert_gen_date_time
          var key = row.device_id + '_' + row.alert_gen_date_time;

          // existence check ! very efficient.
          if (!(key in keys[row.alert_type])) {
            // does not exist yet: adds it, and update your hash.
            keys[row.alert_type][key] = row;
            alerts[row.alert_type].push(row);
          }
        }

        // And now displayal
        DisplayAlerts(alerts)
     }
...
function DisplayAlerts(alerts) {
  for (var key in alerts) {
     var array = alerts[key];

     // My hypothesis is that rendering of a given alert type is inside a node with the kind as css ID.
     $('#'+key+' .caption').html('Alerts(' +  array.length + ')');
     if (array.length != 0) {
       // Fast HTML string: using an array is better than concatenating multiple strings.
       var content = ['<tr class="ui-widget-header"> <th> Depot </th> <th> Route </th> <th> Schedule </th> <th> Trip Number </th><th>Trip Direction</th> <th> Alert Summary</th> <th> Alert Details </th> <th> Generated On </th> </tr>'];
       for (var i = 0; i < OverSpeedAlerts.length; i++) {
         // optimize by accessing your item in array only once.
         var alert = array[i];
         content.push('<tr> <td>', 
            alert.depot_name, 
            '</td> <td>', 
            alert.route_name,
            '</td> <td>',
            alert.schedule_no,
            '</td> <td>',
            alert.trip_number,
            '</td> <td>,
            alert.trip_direction,
            '</td><td> ',
            alert.alert_sub,
            '</td><td title="',
            ConvertToValidTooltip(alert.alert_msg),
            '" style="text-decoration:underline;cursor:pointer;">Place mouse pointer to view message </td><td>',
            new Date(alert.alert_gen_date_time * 1000),
            '</td> </tr>'];
        }
        // Do not select multplie time your table node: it better to store it in a variable.
        $('#' + key + ' table').html(content.join(''));
     }
  }

Happy coding ! 快乐的编码!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM